python刷題Leetcode1-30

知識預熱:
python內置類型的時間複雜度
單向鏈表
python數據結構內置方法的時間複雜度

  1. Two Sum
    兩數==target
    方法二更好
    題1,對時間複雜度有要求O(n),所以維護一個字典,遍歷過的數值放在字典中,直接遍歷時候查找字典中有沒有出現,查找字典時間複雜度是O(1),所以O(n)*O(1) = O(n),滿足要求。
nums = [0, 1, 2, 7, 11, 15]
target = 9

def chek(nums, target):
    dict1 = {}
    for i, ele in enumerate(nums):
        if (target-ele) in dict1:
            return dict1[target-ele], i
        else:
            dict1[ele] = i

print(chek(nums, target))

下面方法和上面方法一樣,但是內存稍稍省下0.1M

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        dict = {}
        for i in range(len(nums)):
            if dict.get(target-nums[i]) == None:
                dict[nums[i]] = i
            else:
                return dict[target-nums[i]], i

方法二,不用維護一個字典的開銷

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        for i in range(len(nums)):
            if (target-nums[i]) in nums[i+1:]:
            	# 這裏返回加i+1是因爲nums[i+1:]計數又是從0開始了
                return i, nums[i+1:].index(target-nums[i])+i+1

感覺方法二的if ele in list的時間複雜度就是O(n),所以不對,這道題應該是需要維護哈希表。
2. Add Two Numbers
題2,Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
#    基本思路是兩個單項列表先取數字,然後求和,再放入向列表中。還記得單項列表的構建方法吧

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        cur = l1
        sum = 0
        idx = 0
        while cur:
            sum += cur.val*(10**idx)
            cur = cur.next
            idx += 1
        
        cur = l2
        idx = 0
        while cur:
            sum += cur.val*(10**idx)
            cur = cur.next
            idx += 1
        
        if sum == 0:
            return ListNode(0)
        else:
            self.head = ListNode(sum%10)
            cur = self.head
            sum //= 10
            while sum > 0:
                cur.next = ListNode(sum%10)
                cur = cur.next
                sum //= 10
            return self.head
  1. Longest Substring Without Repeating Characters
    題3,
#基本思路是維護left和right兩個指針,max_num,
#一個集合,先移動右指針,不在集合中則加入集合裏,
#否則移動左指針,並右指針=左指針。
#用集合是因爲集合的查詢速度是o(1)!!

class Solution(object):
   def lengthOfLongestSubstring(self, s):
       """
       :type s: str
       :rtype: int
       """
       l = r = 0; set1= set()
       max = 0
       while r < len(s) and r < len(s):
           if not s[r] in set1:
               set1.add(s[r])
               r += 1
               if max < len(set1):
                   max = len(set1)
           else:
               l += 1
               r = l
               set1 = set()
       return max
  1. Median of Two Sorted Arrays
    題4, The overall run time complexity should be O(log (m+n))我並沒有注意到這句話,但是結果竟然通過了。我自算的時間複雜度應該是 O( (m+n)log(m+n) )+ O(m).
class Solution:
   def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
       nums1.extend(nums2)
       nums1.sort()
       if not len(nums1)%2:
           n = len(nums1)//2
           return (nums1[n-1]+nums1[n])/2
       else:
           return nums1[len(nums1)//2]
  1. Longest Palindromic Substring
    用的是馬拉車算法,原理鏈接
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if len(s) == 1:
            return s
        b = "$#"
        for i in s:
            b += i
            b += "#"
        maxr = 0;idx = -1
        for i in range(3,len(b)):
            r = 1
            while (i+r)<len(b) and (i-r)>=0:
                if b[i-r] == b[i+r]:
                    r += 1
                else:
                    break
            (maxr,idx) = (r,i) if maxr<=r else (maxr,idx)
            # 起點, 最大長度
            # (idx-maxr)//2, axr-1
        return s[(idx-maxr)//2: (idx-maxr)//2 + maxr-1]
  1. ZigZag Conversion
    我用的方法時間超出限制,我分別考慮了頭、中、尾三種情況,需要改進算法。
class Solution:
    def convert(self, s: str, numRows: int) -> str:
        a = ""
        gap = (numRows-2)*2+2
        for i in range(numRows):
            # 頭情況
            if i == 0:
                n = 0
                while n*gap < len(s):
                    a += s[n*gap]
                    n += 1

            # 中間的情況
            if i>0 and i<numRows-1:
                n = 1
                a += s[i]
                while n*gap+i < len(s) or n*gap-i < len(s):
                    if n*gap-i < len(s):
                        a += s[n*gap-i]
                    if n*gap+i < len(s):
                        a += s[n*gap+i]
                    n += 1

            # 尾情況
            if i == numRows-1:
                bg = numRows-1
                n = 0
                while n*gap+bg < len(s):
                    a += s[n*gap+bg]
                    n += 1
        return a

上面方法耗時超限制,改進思路,按照遍歷放入的思想來實現。代碼,核心思想是控制向下走或者向上走,然後放入對應的行。

s = "PAYPALISHIRING"

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1:
            return s
        s1 = [''] * numRows
        dir = 1
        countn = 0
        for i in range(len(s)):
            if countn == 0:
                s1[countn] += s[i]
                dir = 1
                countn += dir

            elif countn == numRows-1:
                s1[countn] += s[i]
                dir = -1
                countn += dir

            else:
                s1[countn] += s[i]
                countn += dir
        return "".join(s1)


solu = Solution()
s1 = solu.convert(s, 3)
print(s)
print(s1)

改進後通過,內存消耗控制很好。運行速度到112ms。
更近一步:
思考用列表[] .append()的方法可能會提高計算速度,

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1:
            return s
        s1 = []
        for i in range(numRows):
            s1.append([])
        dir = 1
        countn = 0
        for i in range(len(s)):
            if countn == 0:
                s1[countn].append(s[i])
                dir = 1
                countn += dir

            elif countn == numRows-1:
                s1[countn].append(s[i])
                dir = -1
                countn += dir

            else:
                s1[countn].append(s[i])
                countn += dir
        return "".join(j for i in s1 for j in i)

結論:果然[].append(“str_”)的效率比“”+str_效率高,列表擴展效率比字符串擴展效率高。運行耗時提高到100ms
下面在上面代碼基礎上進行精簡,減少一點內存消耗。

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1:
            return s
        s1 = []
        for i in range(numRows):
            s1.append([])
        dir = 1
        countn = 0
        for i in range(len(s)):
            s1[countn].append(s[i])
            countn += dir
            if countn == 0:
                dir = 1
            if countn == numRows-1:
                dir = -1
        return "".join(j for i in s1 for j in i)
  1. 整數反轉
class Solution:
    def reverse(self, x: int) -> int:
        x = int(str(x)[::-1]) if x>=0 else -int(str(x)[1:][::-1])
        if x>-2**31 and x<(2**31)-1:
            return x
        else:
            return 0
  1. 字符串轉換整數 (atoi)
#這道題應該仔細看看題目要求,實現並不難,坑很多。
#還是正則表達式來的最痛快,規則實現需要考慮的細節太多。
#代碼不是我的思路,[來自](https://blog.csdn.net/coder_orz/article/details/52053932)
class Solution(object):
    def myAtoi(self, str):
        """
        :type str: str
        :rtype: int
        """
        str = str.strip()
        try:
            res = re.search('(^[\+\-]?\d+)', str).group()
            res = int(res)
            res = res if res <= 2147483647 else 2147483647
            res = res if res >= -2147483648 else -2147483648
        except:
            res = 0
        return res

正則表達式忘了不少了, 拾起來。
9. 迴文數
這道題進階版本是不用str,可提速。

class Solution:
    def isPalindrome(self, x: int) -> bool:
        return x>=0 and str(x) == str(x)[::-1]

進階版本如下,思想是把數字倒過來。

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x<0:return False
        elif x == 0:return True
        else:
            temp = 0
            t_x = x
            while x>0:
                temp = 10*temp + x%10
                x //= 10
            return temp == t_x

雖然內存沒省,但運算速度提升了。

  1. Regular Expression Matching
    這道題屬於困難,用正則模塊可以實現,但是這不是本題考察目的。
class Solution:
    def isMatch(self, s, p):
        if not s:return False
        res = re.match(p, s)
        if res == None:
            return False
        else:
            return res.group() == s
預留地
找到了思路  https://www.cnblogs.com/Jessey-Ge/p/10993447.html
  1. Container With Most Water
    左右兩個遊標來尋找最大的體積。哪個遊標高度小就移動哪個。時間複雜度O(n)
class Solution(object):
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        l = 0; r = len(height)-1
        max_vol = 0
        while l < r:
            v= min(height[r], height[l])*(r-l)
            max_vol = v if max_vol<v else max_vol
            if height[r] >= height[l]:
                l += 1
            else:
                r -= 1
        return max_vol
  1. Integer to Roman
    這道題的思想,列出羅馬數字和數字的所有對應字典,搞清對應關係,做減法。是人生嗎。
    解法
    #python2中有錯誤,但是python3卻可以通過。
class Solution(object):
   def intToRoman(self, num):
       """
       :type num: int
       :rtype: str
       """

       dic  = { "M":1000, "CM":900, "D":500, "CD":400, "C":100, "XC":90, "L":50,"XL":40, "X":10, "IX":9, "V":5,"IV":4 ,"I":1         }
       ele = ""
       for key,item in dic.items():
           while num >= item:
               num -= item
               ele += key

       return ele

  1. RomanToInterger
    思路:判斷相鄰的左邊數和右邊數:左邊>右邊,取負數,左邊<右邊,取正數。最後數字相加。
class Solution:
    def romanToInt(self, s):
        # dic = {"M": 1000, "CM": 900, "D": 500, "CD": 400, "C": 100, "XC": 90, "L": 50, "XL": 40, "X": 10, "IX": 9, "V": 5, "IV": 4, "I": 1}
        dic = {"M": 1000, "D": 500, "C": 100, "L": 50,  "X": 10, "V": 5, "I": 1}
        num = 0
        for i in range(len(s)-1):
            temp = dic[s[i]] if dic[s[i]]>=dic[s[i+1]] else -1*dic[s[i]]
            num +=temp
        num += dic[s[-1]]
        return num

solu = Solution()
print(solu.romanToInt("XC"))
  1. Longest Common Prefix
    這道題的解法來自網絡,對min函數用法值得我學習。
    最長的共同前綴,思路:找到最短的字符串,一個個字符在其他字符串中比較是不是相同,不同返回之前相同部分
class Solution(object):
   def longestCommonPrefix(self, strs):
       """
       :type strs: List[str]
       :rtype: str
       """
       if not strs:
           return ""
       shotstr = min(strs, key=len)
       
       for i, letter in enumerate(shotstr):
           for other in strs:
               if other[i] == letter:
                   pass
               else:
                   return shotstr[:i]
       return shotstr
  1. 3Sum
    這段代碼TLE。

class Solution(object):
    def twoSum(self, nums, target):
        dict = {}
        temp = []
        for i in range(len(nums)):
            if dict.get(target-nums[i])  == None:
                dict[nums[i]] = i
            else:
                temp.append([target-nums[i], nums[i]])
        return temp

    def threeSum(self, nums):
        nums.sort()
        # print(nums)
        result = []
        temp = []
        for i in range(len(nums)-2):
            re = self.twoSum(nums[i+1:], -nums[i])
            if re:
                for j,k in re:
                    result.append([nums[i], j, k])
        for i in result:
            if i not in temp:
                temp.append(i)
        return temp

這是網上的一種寫法,時間複雜度沒有超限。估計是字典的原因。

class Solution:
    def twoSum(self, nums, target):
        idxDict = dict()
        idx_list = []
        for idx, num in enumerate(nums):
            if target - num in idxDict:
                idx_list.append([idxDict[target - num], idx])
            idxDict[num] = idx
        return idx_list

    def threeSum(self, num):
        num.sort()
        res = dict()
        result = []
        for i in range(len(num)-2):  # 遍歷至倒數第三個,後面兩個指針
            if (i == 0 or num[i] > num[i-1]) and num[i] <= 0:  # 只檢索不重複並且目標數(第一個數)小於等於0的情況
                left = i + 1; 
                # right = len(num) - 1
                result_idx = self.twoSum(num[left:], -num[i])
                for each_idx in result_idx:  # 數組後方切片後給twoSum
                    each_result = [num[i], num[each_idx[0]+(i+1)], num[each_idx[1]+(i+1)]]
                    if str(each_result) not in res:
                        res[str(each_result)] = each_result
        for value in res.values():
            result.append(value)
        return result    
  1. 3Sum Closest
    思路:外循環先固定一個數字下標是i,內循環左右兩個指針指向i+1和最後一個數字。
    比較三個數字的和,等於target返回,否則找和target的差值絕對值最小的的和。內循環移動指針的原則是:如果和比target小,就移動左指針(增加和), 如果比target大就移動右指針(減小和),最後輸出差值最小的和。
    時間複雜度:外循環是O(n),內循環是O(n),所以O(n^2)
class Solution(object):
	def threeSumClosest(self, nums, target):
		"""
		:type nums: List[int]
		:type target: int
		:rtype: int
		"""
		n = len(nums)
		if n < 3: return 0
		nums = sorted(nums)
		val = nums[0] + nums[1] + nums[n-1]
		diff = abs(val - target)
		for i in range(n-2):
			# 兩個指針的起點
			l = i + 1; r = n - 1
			while l < r:
				temp_sum = nums[i] + nums[l] + nums[r]
				if temp_sum == target: return temp_sum
				elif abs(temp_sum - target) <= diff:
					diff = abs(temp_sum - target)
					val = temp_sum
				if temp_sum > target: # 目標需要減少
					r -= 1 # 一次挪動一個指針
				elif temp_sum < target: # 目標需要增加
					l += 1
		return val
  1. Letter Combinations of a Phone Number
    思路:深度優先遍歷,注意控制返回點。這道題的解法來自於博客,解法不是我的,瞻仰。
"""深度優先遍歷來自於:https://blog.csdn.net/XX_123_1_RJ/article/details/80947129"""
這個人的解法很好:值得學習https://blog.csdn.net/XX_123_1_RJ/article/details/80947129
class Solution:
    def letterCombinations(self, digits):
        if not digits: return []  # 如果爲空,返回空列表
        dict = {'1': [''],
                '2': ['a', 'b', 'c'],
                '3': ['d', 'e', 'f'],
                '4': ['g', 'h', 'i'],
                '5': ['j', 'k', 'l'],
                '6': ['m', 'n', 'o'],
                '7': ['p', 'q', 'r', 's'],
                '8': ['t', 'u', 'v'],
                '9': ['w', 'x', 'y', 'z']}
        def lcb(digits, dict, idx, lis, strl):
            if idx == n:
                lis.append(strl)
                return
            for ele in dict[digits[idx]]:
                lcb(digits, dict, idx+1, lis, strl+ele)

        lis = []
        n = len(digits)
        lcb(digits, dict, 0, lis, "")

        return lis

if __name__ == '__main__':
    digits = '92'
    solu = Solution()
    print(solu.letterCombinations(digits))

這段代碼很好,瞻仰了,執行效率最快。來自於博客

# @Time   :2018/7/7
# @Author :LiuYinxing
from functools import reduce


class Solution:
    def letterCombinations(self, digits):
        if not digits: return []  # 如果爲空,返回空列表
        dict = {'1': [''],
                '2': ['a', 'b', 'c'],
                '3': ['d', 'e', 'f'],
                '4': ['g', 'h', 'i'],
                '5': ['j', 'k', 'l'],
                '6': ['m', 'n', 'o'],
                '7': ['p', 'q', 'r', 's'],
                '8': ['t', 'u', 'v'],
                '9': ['w', 'x', 'y', 'z']}
        return reduce(lambda acc,digit:[i+j for j in acc for i in dict[digit]], digits, ("",))


if __name__ == '__main__':
    digits = '92'
    solu = Solution()
    print(solu.letterCombinations(digits))
  1. 4Sum
又是數字之和,留着回來加深印象吧。
自留地
  1. Remove Nth Node From End of List
    ♠♠♠♠
    思想:List這裏是單向鏈表的的意思,前後兩個指針相差n個元素,後面元素的next爲空時表示到尾,左邊指針的的next就是要刪除的元素,我記得怎麼刪除,你也會吧。注意:一種特殊情況是要刪除的剛好是頭節點,所以優先判斷有指針是不是移動到了空。
    前輩們的有一種解法是先構造一個node掛在head前面,這樣做的好處是不用判斷我在上面提到的注意情況了。
class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        p1 = p2 = head
        for i in range(0,n,1): p1 = p1.next
        # if the delete element is just head
        if not p1: return head.next
        while p1.next:
            p1= p1.next; p2=p2.next
        p2.next = p2.next.next
        return head
  1. Valid Parentheses

這道題考查的是棧的知識,即將入棧的元素和棧頂元素比較。下面空間複雜度是O(n)

class Solution:
    def isValid(self, s: str) -> bool:
        stack = ["Null"]
        dic = { ')' :'(', ']' :'[', '}':'{' }
        for i in s:
            if dic.get(i, None)== stack[-1]:
                stack.pop(-1)
            else:
                stack.append(i)
        return stack==["Null"]

C

int isValid(char * s){
    if (s == NULL || s[0] == '\0') return 1;
    char *stack = (char*)malloc(strlen(s)+1); int top =0;
    for (int i = 0; s[i]; ++i) {
        if (s[i] == '(' || s[i] == '[' || s[i] == '{') stack[top++] = s[i];
        else {
            if ((--top) < 0)                      return 0;  // 先減減,讓top指向棧頂元素
            if (s[i] == ')' && stack[top] != '(') return 0;
            if (s[i] == ']' && stack[top] != '[') return 0;
            if (s[i] == '}' && stack[top] != '{') return 0;
        }
    }
    if (top>0)  // 入棧++, 出棧--, 可以等於0
    {return 0;}
    return 1;
}

空間複雜度優化到O(1), 大體思路是用棧的思想,但是用指針思想優化掉棧的空間,即記錄要入棧的元素座標和入棧元素個數。
下面方法還是有問題,"(([]){})"這樣的輸入無法解決,能解決{}{}, {{}}

class Solution(object):
    """
    o(1)
    idx 控制入棧的元素下標
    sum 統計在棧中元素個數
    """
    def isValid(self, s):# -> bool:
        dic = {")":"(", "}":"{", "]":"["}
        # ls = []
        idx = -1
        sum = 0
        n = len(s)
        if n == 0 or s==" ": return True
        for i in range(n):
            if s[i] in list(dic.values()):
                # ls.append(s[i])
                idx += 1  # 座標入棧
                sum += 1
            else:
                # if len(ls) == 0:
                if sum == 0:  # 棧空了
                    return False
                else:
                    if s[idx] != dic[s[i]]:
                        return False # 不配對
                    else:
                        # ls.pop(-1)
                        sum -= 1
                        if sum ==0:  # 棧空,準備入棧座標更新
                            idx = i
                        else:
                            idx -= 1 # 棧不空,彈出一個元素
        if sum == 0: # 棧中爲空
            return True
        else:
            return False

s = Solution()
print(s.isValid("{}{{{}}}"))
  1. Merge Two Sorted Lists
    鏈表結構。
    用遞歸方式實現。時間複雜度O(n+m),m、n是鏈表1鏈表2的長度。
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
   def mergeTwoLists(self, l1, l2):
       """
       :type l1: ListNode
       :type l2: ListNode
       :rtype: ListNode
       """
       if l1 is None or l2 is None:
           return l1 or l2
       if l1.val > l2.val:
           l2.next = self.mergeTwoLists(l2.next, l1)
           return l2
       else:
           l1.next = self.mergeTwoLists(l1.next, l2)
           return l1

Generally speaking,我更想使用一個新的鏈表,我並不喜歡上面的解法會破壞L1,L2原有的鏈表結構,下面多用一個鏈表的開銷。

class Solution:
    def mergeTwoListsRecursion(self, l1: ListNode, l2: ListNode) -> ListNode:
        if l1 == None or l2 == None
            return l2 or l1
        
        # 新鏈表    
        p = ListNode(0)   
        if(l1.val<l2.val):
            p = l1
            p.next = self.mergeTwoListsRecursion(l1.next, l2)
        else:
            p = l2
            p.next = self.mergeTwoListsRecursion(l1, l2.next)
        
        return p

另附傳統解法的思路(算是歸併排序):新建一個空鏈表,在兩個鏈表中找node.val小的節點,然後掛節點,往後移動指針。兩個鏈表不一定一樣長,最後把剩下的節點都掛上。
22. Generate Parentheses
♠♠♠
思路:遞歸+深度優先遍歷。
括號的總數只能是2n個。
組合括號的字符串原則:在[1,2n]任意索引位置的左括號要大於等於右括號。
遞歸方案:左括號右括號剩餘都是零的時候返回,左括號有剩餘,則先+左括號(右括號剩餘大於左括號,加右括號)。
思路和代碼來自前輩

class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        self.res = []
        self.generateParenthesisIter('', n, n)
        return self.res
    def generateParenthesisIter(self, mstr, r, l):
        if r ==0 and l==0:
            logger.info("1-l,r[%d, %d] mstr:%s"%(l, r, mstr))
            self.res.append(mstr)
        if l>0:
            logger.info("2-l,r[%d, %d] mstr:%s"%(l, r, mstr))
            self.generateParenthesisIter(mstr+'(', r, l-1)
        if r>0 and r>l:
            logger.info("3-l,r[%d, %d] mstr:%s"%(l, r, mstr))
            self.generateParenthesisIter(mstr+')', r-1, l)

附上遞歸日誌,日誌也可以用重定向來實現。

2019-08-20 11:20:56,872 - 2-l,r[3, 3] mstr:
2019-08-20 11:20:56,872 - 2-l,r[2, 3] mstr:(
2019-08-20 11:20:56,872 - 2-l,r[1, 3] mstr:((
2019-08-20 11:20:56,872 - 3-l,r[0, 3] mstr:(((
2019-08-20 11:20:56,872 - 3-l,r[0, 2] mstr:((()
2019-08-20 11:20:56,872 - 3-l,r[0, 1] mstr:((())
2019-08-20 11:20:56,872 - 1-l,r[0, 0] mstr:((()))
2019-08-20 11:20:56,872 - 3-l,r[1, 3] mstr:((
2019-08-20 11:20:56,873 - 2-l,r[1, 2] mstr:(()
2019-08-20 11:20:56,873 - 3-l,r[0, 2] mstr:(()(
2019-08-20 11:20:56,873 - 3-l,r[0, 1] mstr:(()()
2019-08-20 11:20:56,873 - 1-l,r[0, 0] mstr:(()())
2019-08-20 11:20:56,873 - 3-l,r[1, 2] mstr:(()
2019-08-20 11:20:56,873 - 2-l,r[1, 1] mstr:(())
2019-08-20 11:20:56,873 - 3-l,r[0, 1] mstr:(())(
2019-08-20 11:20:56,873 - 1-l,r[0, 0] mstr:(())()
2019-08-20 11:20:56,873 - 3-l,r[2, 3] mstr:(
2019-08-20 11:20:56,873 - 2-l,r[2, 2] mstr:()
2019-08-20 11:20:56,873 - 2-l,r[1, 2] mstr:()(
2019-08-20 11:20:56,873 - 3-l,r[0, 2] mstr:()((
2019-08-20 11:20:56,873 - 3-l,r[0, 1] mstr:()(()
2019-08-20 11:20:56,873 - 1-l,r[0, 0] mstr:()(())
2019-08-20 11:20:56,873 - 3-l,r[1, 2] mstr:()(
2019-08-20 11:20:56,873 - 2-l,r[1, 1] mstr:()()
2019-08-20 11:20:56,873 - 3-l,r[0, 1] mstr:()()(
2019-08-20 11:20:56,874 - 1-l,r[0, 0] mstr:()()()
  1. Merge k Sorted Lists
    下面這是用循環+合併兩個列表的方法,但是TLE,很多鏈表要重複再次參與排序。時間複雜度接近O(k*n), n是鏈表元素總個數,k是len(lists)
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None


class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        if not lists:
            return None
        temp = []
        for i in range(len(lists)):
            temp = self.mergeTwoLists(temp, lists[i])
        return temp

    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        if not l1 or not l2:
            return l1 or l2
        elif l1.val > l2.val:
            l2.next =self.mergeTwoLists(l1, l2.next)
            return l2
        else:
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1  

分治+遞歸+合併,O(nlog(k)),當然不是我的思路

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        if not lists:
            return None
        num = len(lists)
        return self.merge(lists, 0, num-1)
    def merge(self, lists, l, r):
        if l == r:
            return lists[l]
        mid = l + (r-l) // 2
        l1 = self.merge(lists, l, mid)
        l2 = self.merge(lists, mid+1, r)
        return self.mergeTwoLists(l1, l2)
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        if not l1 or not l2:
            return l1 or l2
        elif l1.val > l2.val:
            l2.next =self.mergeTwoLists(l1, l2.next)
            return l2
        else:
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1
  1. Swap Nodes in Pairs
    ♠♠
    我多次中毒的一道題,思路:首先得有個不變的頭結點返回,不妨新建一個node做爲頭。其次左右指針換了位置要搞注意。最後,移動指針時候要注意None可沒有next屬性,判斷好指針的終點。
    不妨以長度爲3的鏈表爲例思考清楚。
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None


class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head: return None # only 0 node
        node = ListNode(0)
        node.next = head
        pre = node
        l, r = head, head.next
        while l and r:
            l.next = r.next
            r.next = l
            pre.next = r

            pre = l
            l = l.next
            if l: r = l.next
        return node.next
  1. Reverse Nodes in k-Group

  2. Remove Duplicates from Sorted Array
    題目要求:返回不重複數字的個數n,並且nums的前n個是不重複的元素。
    思路:左右兩個遊標(一個可以用range裏的i),左右不一樣就左邊遊標+1的元素賦值右遊標的元素,左右遊標移動。否則只移動右遊標。

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        j = 0
        for i in range(1, len(nums)):
            if nums[j] != nums[i]:
                nums[j+1] = nums[i]
                j += 1
        return j+1

solu = Solution()
result = solu.removeDuplicates([1,2,3,3,3,4,5,6,7,7,8])
print(result)
  1. Remove Element
    思路:只要把和指定元素不同的element移動到數列頭就可以了。
    實現:左右兩個指針,左邊數值和val不同時候右指針的數值移動到做指針並且兩指針右移,否則只移動右指針。
class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        j = 0
        for i in range(len(nums)):
            if nums[i] != val:
                nums[j] = nums[i]
                j += 1
            else:
                pass
        return j

另一種方法,從後操作列表。原因:前面刪除列表會導致index更新,後面的元素往前排。從後面開始刪就不會漏檢索。

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        j=len(nums)
        for i in range(j-1,-1,-1):
            if nums[i]==val:
                nums.pop(i)    
        return len(nums)
  1. Implement strStr()
    下面解法沒啥好說的。
    注:list和str都有.index內置方法,好用。
class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        try:
            return haystack.index(needle)
        except:
            return -1

下面寫個遍歷的暴力破解,但是TLE。可以用KMP思想來優化。

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        for i in range(len(haystack)):
            if haystack[i] == needle[0]:
                for j in range(len(needle)):
                    if (i+j) > (len(haystack) - 1): break
                    if needle[j] != haystack[i + j]: break
                    else:pass
                else:
                    return i
        return -1

solu = Solution()
print(solu.strStr("helll0", "lll"))

這道題的收穫,切片比雙循環快的多。
for外接else:如果for 執行沒有打斷執行else,否則不執行else。
下面切片代碼來自

 class Solution:
 	def strStr(self, haystack: 'str', needle: 'str') -> 'int':
 	    for i in range(0, len(haystack) - len(needle) + 1):
 	        if haystack[i:i+len(needle)] == needle:
 	            return i
     	return -1
  1. Divide Two Integers
    思路:不能用乘法,取餘和除法,那就減法。整除的結果意義是被除數中有多少個除數,如果一次減一個除數,時間會超限(2**31/1)。如果除數倍增,那麼速度會極大提高。
    這道題還要考慮32位整數的上限下限。以及除數、被除數的正負。
class Solution:
   def divide(self, dividend, divisor):
       """
       :type dividend: int
       :type divisor: int
       :rtype: int
       """
       MAX_INT = 2147483647
       positive = 1 if ((dividend>0 and divisor>0)or(dividend<0 and divisor<0)) else -1
       num_of_divisor = 0 # 存放除數個數
       dividend,  divisor = abs(dividend), abs(divisor)
       while dividend >= divisor:
           dsor = divisor
           num = 1
           while dsor << 1 <= dividend:
               dsor <<= 1 # 每次增加兩倍
               num <<= 1 # 每一輪產生多少除數
           dividend -= dsor
           num_of_divisor += num
       num_of_divisor *= positive
       return min(max(num_of_divisor, -MAX_INT-1), MAX_INT)


solu = Solution()
t = solu.divide(121, -4)
print(t)
  1. Substring with Concatenation of All Words
    超過我的水平,先留着。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章