LeetCode刷题之路(三)

LeetCode35搜索插入位置

算法思路:我认为这这道题就是考察二分查找法。

常见的二分查找考察的方法有:

  • 给定一个有序的数组,查找target值是否在数组中
  • 给定一个有序数组,查找target第一次出现的下标(同样也有最后一个出现的下标)
  • 给定一个有序数组,查找最接近target且大于target的数的下标(最接近target且小于target的数的下标)

这个链接有整理好关于二分查找算法的问题的

说回这道题,这道题需要我们找回数组中target值的索引,如果没有则找到插入位置。其实这个问题就是上面第一个问题—给定一个有序的数组,查找target值是否在数组中,和第三个问题—给定一个有序数组,查找最接近target且大于target的数的下标的结合体。至于应该插在第一位还是最后一位直接可以进行特判(从算法复杂度的角度来说,出现这两种情况是二分查找最差的情况)。

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
# if target < nums[0]:
# return 0
# if target > nums[-1]:
# return len(nums)
        low = 0
        high = len(nums) - 1
        while(low <= high):
            middle = low +((high - low)>>1)
            if nums[middle] == target:
                return middle
            elif nums[middle] < target:
                low = middle +1
            else:
                high = middle-1
        return high + 1

LeetCode38报数

算法思路:这道题如果读懂了题意,那么就这个问题就简单了。

题意:比如说“1211”,就是一个1,一个2,两个1组成,所以下一个报数我们要输出“111221”,再比如说“111221”,由三个1,二个2,一个1组成,所以下一个我们要输出”312211“

每一项报数都是基于前一项的结果生成的。统计相同的数字,当遇到不相同的数字就要输出结果,然后继续统计下一个数字。我的算法需要注意的是在循环体中当j等于最后一个数了必须要输出当前的字符串

class Solution:
    def countAndSay(self, n: int) -> str:
        d = {}
        for i in range(1, 31):
            d.setdefault(i, "")
        d[1] = '1'
        d[2] = '11'
        for i in range(3, 31):
            count = 0
            tmp_case = ""
            tmp = d[i-1][0]
            for j in range(len(d[i-1])):
                if tmp == d[i-1][j]:
                    count += 1
                else:
                    tmp_case = tmp_case+str(count)+str(tmp)
                    tmp = d[i-1][j]
                    count = 1
                if j == (len(d[i - 1]) - 1):
                    tmp_case = tmp_case + str(count) + str(tmp)
            d[i] = tmp_case
        return d[n]

LeetCode2两数相加

算法:就是模拟两个数相加,只是需要考虑不同情况的进位。

具体的进位有普通的进位;两个数位数一样,最后的一位相加后产生进位;两个数位数不一样,比如123,9740中,“3”和“7”相加产生进位,“9”加上之前进位的“1”还要产生进位。这几种进位情况考虑到了就可以了。

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        r = ListNode(0)
        p = r
        count = 0
        while(l1 and l2):
            tmp = ListNode(0)
            tmp.val = l1.val + l2.val if count == 0 else l1.val + l2.val +1
            count = 0
            if tmp.val >= 10:
                count = 1
                tmp.val -= 10
            p.next = tmp
            p = p.next
            l1 = l1.next
            l2 = l2.next 
        if count == 1 and l1 is None and l2 is None:
            tmp = ListNode(1)
            p.next = tmp
            p = p.next
            return r.next
        while l1:
            tmp = ListNode(0)
            tmp.val = l1.val if count == 0 else l1.val +1
            count = 0
            if tmp.val >= 10:
                count = 1
                tmp.val -= 10
            p.next = tmp
            p = p.next
            l1 = l1.next
        if count == 1:
            tmp = ListNode(1)
            p.next = tmp   
        while l2:
            tmp = ListNode(0)
            tmp.val =l2.val if count == 0 else l2.val +1
            count = 0
            if tmp.val >= 10:
                count = 1
                tmp.val -= 10
            p.next = tmp
            p = p.next
            l2 = l2.next
        if count == 1:
            tmp = ListNode(1)
            p.next = tmp  
        return r.next

LeetCode3无重复字符的最长子串

算法思路:最开始写了个O(n^3)的暴力算法。最后看了下讨论里面发现有一个新的思路:

将每一个字符加入一个字符串中,依次检查字符串的字符是否已经存在该子串中,没有加加入,当前子串匹配失败时,子串并不需退回去重新匹配,而是将找到当前子串中失配的位置,从下一位重新开始匹配(因为子串中已经存在个相同的字符了,所以从下一个开始匹配) 每次发生失配就返回当前子串的长度。

tips:当整个字符串检索完毕还要输出还要更新一次无重复字符串长度,因为在for循环中只有发生失配才会更新无重复字符串长度。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        str = ''  
        max_count = 0
        for i in range(len(s)):
            if s[i] not in str:
                str +=  s[i]
            else:
                if max_count < len(str):
                    max_count = len(str)
                str = str[str.index(s[i])+1:]
                str += s[i]
        if max_count < len(str):
            max_count = len(str)
        return max_count

LeetCode5最长回文子串

算法思路,这道题有很多种思路,我使用动态规划的方法来解决。

当我们已经判断一个字符串是一个回文串时,假设我们现在已经获得下标从 i i i j j j的字符串,即 s i − 1 , j − 1 s_{i-1,j-1} si1,j1是一个回文串,如果 s i =    s j s_{i}=\;s_{j} si=sj,那么 s i , j ​ s_{i,j}​ si,j就是一个回文串,这种情况适用于回文子串长度大于等于3。当长度为1,和2时得初始化。所以我们可以得到一个这样的状态转移方程:

d p [ i ] [ j ] = { 1 d p [ i + 1 ] [ j − 1 ] = 0    a n d    s i = s j 0 d p [ i + 1 ] [ j − 1 ]    ! = 0    o r    s i    ! = s j ​ dp\lbrack i\rbrack\lbrack j\rbrack=\left\{\begin{array}{lc}1&dp\lbrack i+1\rbrack\lbrack j-1\rbrack=0\;and\;s_i=s_j\\0&dp\lbrack i+1\rbrack\lbrack j-1\rbrack\;!=0\;or\;s_i\;!=s_j\end{array}\right.​ dp[i][j]={10dp[i+1][j1]=0andsi=sjdp[i+1][j1]!=0orsi!=sj

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        if s == "":
            return s
        dp = [[0 for i in range(length)] for j in range(length)]
        max_length = 0
        count = 1
        for i in range(length): # 初始化dp数组
            dp[i][i] = 1
            if i < length -1:
                if s[i] == s[i+1]:
                    dp[i][i+1] = 1
                    #dp[i+1][i] = 1
                    count = 2
        if length < 3:
            if count == 2:
                return s
            elif dp[0][0] == 1:
                return s[0]
        for len_substring in range(3, length+1): # 枚举每个子串可能的长度
            for i in range(length+1-len_substring):
                j = i+len_substring-1
                if s[i] == s[j] and dp[i+1][j-1] == 1:
                    dp[i][j] = 1
        index_i = 0
        index_j = 0
        for i in range(length):
            for j in range(length):
                if dp[i][j] == 1:
                    count = j-i
                    if count > max_length:
                        max_length = count
                        index_i = i
                        index_j = j
        return s[index_i:index_j+1]

你可能感兴趣的:(LeetCode)