两数相加

Date: 2020-9-13 周日
image.png

  1. # class ListNode:
  2. # def __init__(self, x):
  3. # self.val = x
  4. # self.next = None
  5. class Solution:
  6. def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
  7. dummy = p = ListNode(None)
  8. s=0
  9. while l1 or l2 or s:
  10. s +=(l1.val if l1 else 0)+(l2.val if l2 else 0)
  11. p.next=ListNode(s % 10)
  12. p= p.next
  13. s //= 10
  14. l1 = l1.next if l1 else None
  15. l2 = l2.next if l2 else None
  16. return dummy.next

采用双指针法,dummy为头指针,p为遍历指针。初始化时将dummy与p赋值为值为空的节点。s用来存储进位信息。在每次循环中,将s与l1 与 l2 的节点值相加,将s的个位数赋值为下一个节点,将s取模作为进位 供下次循环运算使用。
最后返回dummy的next,因为其本身为空节点。
因为有可能l1 、l2长度不同,所以分别需要判断。

无重复字符的最长子串*

Date: 2020-9-14 周一
image.png

暴力求解

  1. class Solution:
  2. def isRepeat(self ,s:List,s_str:str) -> bool:
  3. if len(s)==0:
  4. return True
  5. for s_in in s:
  6. if s_str == s_in:
  7. return False
  8. return True
  9. def lengthOfLongestSubstring(self, s: str) -> int:
  10. length=len(s)
  11. i=0
  12. max=0
  13. while i<length:
  14. nums=[]
  15. j=i
  16. while j<length:
  17. if self.isRepeat(nums,s[j]):
  18. nums.append(s[j])
  19. else:
  20. break
  21. j+=1
  22. if len(nums)>max:
  23. max=len(nums)
  24. i+=1
  25. return max

暴力求解就是先从字符串的头开始遍历,使用双层循环。内层循环查找从头开始到尾的不连续的最大字符串。外循环则是将头缩进一个,并且将当前内循环的最大值与保存的max作比较,择大选择保存。
单纯的暴力虽然能做出来但是效率太差了。
image.png

滑动窗口

什么是滑动窗口?

其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!

如何移动?

我们只要把队列的左边的元素移出就行了,直到满足题目要求!

一直维持这样的队列,找出队列出现最长的长度时候,求出解!

时间复杂度:O(n)

  1. class Solution:
  2. def lengthOfLongestSubstring(self, s: str) -> int:
  3. if not s:return 0
  4. left = 0
  5. lookup = set()
  6. n = len(s)
  7. max_len = 0
  8. cur_len = 0
  9. for i in range(n):
  10. cur_len += 1
  11. while s[i] in lookup: #在窗口中左移,直到s[i]在窗口中不重复
  12. lookup.remove(s[left])
  13. left += 1
  14. cur_len -= 1
  15. if cur_len > max_len:max_len = cur_len
  16. lookup.add(s[i])
  17. return max_len

寻找两个正序数组的中位数

Date: 2020-9-15 周二
image.png

  1. class Solution:
  2. def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
  3. mid=0
  4. nums=[]
  5. n1=len(nums1)-1
  6. n2=len(nums2)-1
  7. while n1>=0 and n2>=0:
  8. if nums1[n1]>nums2[n2]:
  9. nums.append(nums1[n1])
  10. n1-=1
  11. else:
  12. nums.append(nums2[n2])
  13. n2-=1
  14. while n1>=0:
  15. nums.append(nums1[n1])
  16. n1-=1
  17. while n2>=0:
  18. nums.append(nums2[n2])
  19. n2-=1
  20. print(nums)
  21. if len(nums)%2==0:
  22. mid=(nums[int(len(nums)/2)-1]+nums[int(len(nums)/2)])/2
  23. else:
  24. mid=nums[int(len(nums)/2)]
  25. return mid

思想就是先有序合并两个数组。然后直接从有序的数组中查找对应的中位数。

最长回文串*

Date: 2020-9-16 周三
image.png

暴力遍历

  1. class Solution:
  2. def longestPalindrome(self, s: str) -> str:
  3. length=len(s)
  4. if length<2:return s
  5. maxLen=1
  6. begin=0
  7. i=0
  8. #枚举所以长度严格大于1的子串
  9. while i<length-1:
  10. j=i+1
  11. while j<length:
  12. if j-i+1>maxLen and self.validPalindromic(s,i,j):
  13. maxLen=j-i+1
  14. begin=i
  15. j+=1
  16. i+=1
  17. return s[begin:begin+maxLen]
  18. def validPalindromic(self,s:str,left:int,right:int)->bool:
  19. while left<right:
  20. if s[left]!=s[right]:
  21. return False
  22. left+=1
  23. right-=1
  24. return True

暴力搜索匹配就是先将回文串判断函数写出。从字符串s的头部开始,判断所有子串,并且记录下是回文串的最长子串的起始位置和长度,最后通过起始位置和长度截取字符串输出。但是暴力运行效率太低,无法通过测试。
image.png

动态规划*

image.png

  1. class Solution:
  2. def longestPalindrome(self, s: str) -> str:
  3. n = len(s)
  4. dp = [[False] * n for _ in range(n)]
  5. ans = ""
  6. # 枚举子串的长度 l+1
  7. for l in range(n):
  8. # 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
  9. for i in range(n):
  10. j = i + l
  11. if j >= len(s):
  12. break
  13. if l == 0:
  14. dp[i][j] = True
  15. elif l == 1:
  16. dp[i][j] = (s[i] == s[j])
  17. else:
  18. dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
  19. if dp[i][j] and l + 1 > len(ans):
  20. ans = s[i:j+1]
  21. return ans

中心扩展法*

image.png

  1. class Solution:
  2. def expandAroundCenter(self, s, left, right):
  3. while left >= 0 and right < len(s) and s[left] == s[right]:
  4. left -= 1
  5. right += 1
  6. return left + 1, right - 1
  7. def longestPalindrome(self, s: str) -> str:
  8. start, end = 0, 0
  9. for i in range(len(s)):
  10. left1, right1 = self.expandAroundCenter(s, i, i)
  11. left2, right2 = self.expandAroundCenter(s, i, i + 1)
  12. if right1 - left1 > end - start:
  13. start, end = left1, right1
  14. if right2 - left2 > end - start:
  15. start, end = left2, right2
  16. return s[start: end + 1]

Z形变换

Date: 2020-9-19 周六

二维数组法

image.png

  1. class Solution:
  2. def findCols(self,length:int , numRows:int):
  3. mid = numRows*2 - 2 #每组数据的元素个数
  4. cols = 0
  5. cols = int(length / mid) * (numRows - 1) #完整分组所占的列数
  6. #求不完整分组所占的列数
  7. if length % mid == 0: #能够整除
  8. cols +=0
  9. else: #如果不能整除
  10. mid_y = length % mid
  11. if mid_y <= numRows:
  12. cols +=1
  13. else:
  14. cols += (mid_y - numRows +1)
  15. return cols
  16. def convert(self, s: str, numRows: int) -> str:
  17. if numRows == 1:
  18. return s
  19. cols = self.findCols(len(s),numRows) #生成矩阵列数
  20. V = [["#"] * cols for _ in range(numRows)]
  21. index = 0
  22. j = 0
  23. while j < cols:
  24. if index>len(s):
  25. break
  26. for i in range(numRows):
  27. if index <len(s):
  28. V[i][j] = s[index]
  29. index +=1
  30. if i!=0 and i!=numRows-1:
  31. vi = i
  32. vj = j+numRows - i -1
  33. s_index = 2*vj +vi
  34. if vj < cols and s_index < len(s):
  35. V[vi][vj] = s[s_index]
  36. index +=(numRows-2)
  37. j +=(numRows-1)
  38. ans = ""
  39. for i in range(numRows):
  40. for j in range(cols):
  41. if V[i][j] !="#":
  42. ans +=V[i][j]
  43. return ans

我的思路是先生成一个合适的矩阵,在遍历这个矩阵的时候逐个往其中填入相应的字符。最后在遍历矩阵输出。
矩阵的行数由外部指定,列数则通过相应的计算公式得到。时间复杂度和空间复杂度都是n的平方。。。。

字符串转换整数

Date: 2020-9-22 周二
image.png

  1. class Solution:
  2. def judeNumScope(self,num:int) ->int:
  3. if num>0:
  4. if num>=2147483648:
  5. return 2147483647
  6. elif num<0:
  7. if num<=-2147483648:
  8. return -2147483648
  9. return num
  10. def isNumber(self,str:str) :
  11. return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}.get(str,-1)
  12. def myAtoi(self, str: str) -> int:
  13. #去除左边空格
  14. str = str.lstrip()
  15. if str == "":
  16. return 0
  17. symbol = "+"
  18. num = "#"
  19. if self.isNumber(str[0]) == -1 and not(str[0] == "+" or str[0] == "-"):
  20. return 0
  21. index = 0
  22. for s in str:
  23. if s == "-" or s == "+":
  24. if index ==0:
  25. symbol = s
  26. else:
  27. return 0
  28. else:
  29. break
  30. index += 1
  31. str = str[index:len(str)]
  32. for s in str:
  33. if s == "-" or s == "+":
  34. if s != str[0]:
  35. return 0 if num == "#" else self.judeNumScope(int(num)) if symbol=="+" else self.judeNumScope(-int(num))
  36. continue
  37. if self.isNumber(s) == -1:
  38. return 0 if num == "#" else self.judeNumScope(int(num)) if symbol=="+" else self.judeNumScope(-int(num))
  39. if num =="#":
  40. num = s
  41. else :
  42. num+=s
  43. return 0 if num == "#" else self.judeNumScope(int(num)) if symbol=="+" else self.judeNumScope(-int(num))

思路很简单,就是先截取,然后用字符串保留住数值部分,最后再通过int()方法转换成数值。但是需要注意多种特殊情况,比如:”+-1” “++1” “+9999999999999”等。

正则表达式匹配**

Date: 2020-9-22 周二
image.png

别人家的思路:

image.png
image.png
image.png
image.png
image.png
image.png
image.png

  1. class Solution:
  2. def isMatch(self, s: str, p: str) -> bool:
  3. s_len = len(s)
  4. p_len = len(p)
  5. # dp[i][j] 表示 s[:i] 与 p[:j] 是否匹配,各自前 i、j 个是否匹配
  6. dp = [[False] * (p_len + 1) for _ in range(s_len + 1)]
  7. dp[0][0] = True
  8. #就是确定上边最后的base case的情况 s 为空串时 如果p中有*可以干掉一个字符
  9. for j in range(1, p_len + 1):
  10. # 若 p 的第 j 个字符 p[j - 1] 是 '*'
  11. # 说明第 j - 1、j 位可有可无
  12. # 那么如果前 j - 2 个已经匹配上,前 j 个也可以匹配上
  13. if p[j - 1] == '*':
  14. dp[0][j] = dp[0][j - 2]
  15. for i in range(1, s_len + 1):
  16. for j in range(1, p_len + 1):
  17. if p[j - 1] in {s[i - 1], '.'}:
  18. dp[i][j] = dp[i - 1][j - 1]
  19. elif p[j - 1] == '*':
  20. if p[j - 2] in {s[i - 1], '.'}:
  21. dp[i][j] = dp[i][j - 2] or dp[i - 1][j - 2] or dp[i - 1][j]
  22. else:
  23. dp[i][j] = dp[i][j - 2]
  24. return dp[s_len][p_len]

盛最多水的容器

Date: 2020-9-23 周四
image.png

暴力(但是会超时)

  1. class Solution:
  2. def maxArea(self, height: List[int]) -> int:
  3. max = 0
  4. for i in range(len(height)):
  5. for j in range(i+1,len(height)):
  6. num = (j - i) * (height[i] if height[i] < height[j] else height[j])
  7. if num > max:
  8. max = num
  9. return max

双指针法

  1. class Solution:
  2. def maxArea(self, height: List[int]) -> int:
  3. max = 0
  4. hLen = len(height) - 1
  5. i = 0
  6. while i < hLen :
  7. num = (hLen - i) * min(height[i],height[hLen])
  8. if num > max:
  9. max = num
  10. if height[i] < height[hLen]:
  11. i += 1
  12. else:
  13. hLen -= 1
  14. return max

整数转罗马数字

Date: 2020-9-24 周四
image.png

逐位转换

  1. class Solution:
  2. def intToRoman(self, num: int) -> str:
  3. roman = ""
  4. numStr = str(num)
  5. nLen = len(numStr)
  6. for i in range(len(numStr)):
  7. numMid = 10 ** (nLen-1)
  8. Num = int(numStr[i]) * numMid
  9. sym =self.changeStr(numMid)
  10. if Num == 0:
  11. nLen -= 1
  12. continue
  13. if Num == (5 * numMid):
  14. roman += self.changeStr(Num)
  15. elif Num > (5 * numMid): #在左边拼接
  16. if int(numStr[i]) == 9:
  17. symMid = self.changeStr(numMid*10)
  18. for _ in range(10-int(numStr[i])):
  19. roman += sym
  20. roman +=symMid
  21. else:
  22. symMid = symMid = self.changeStr(numMid*5)
  23. roman +=symMid
  24. for _ in range(int(numStr[i])-5):
  25. roman += sym
  26. # sym =self.changeStr(numMid)
  27. else : #在右边
  28. if int(numStr[i]) == 4:
  29. symMid = self.changeStr(5 * numMid)
  30. for _ in range(5-int(numStr[i])):
  31. roman += sym
  32. roman +=symMid
  33. else:
  34. symMid = ""
  35. for _ in range(int(numStr[i])):
  36. roman += sym
  37. nLen -= 1
  38. return roman
  39. def changeStr(self, num:int) ->str:
  40. return {1:"I",5:"V",10:"X",50:"L",100:"C",500:"D",1000:"M"}.get(num,"")

三数之和

Date: 2020-9-24 周四
image.png

暴力(超时)

  1. import numpy as np
  2. class Solution:
  3. def threeSum(self, nums: List[int]) -> List[List[int]]:
  4. list = []
  5. for i in range(len(nums)-2):
  6. for j in range(i+1 , len(nums)-1):
  7. for z in range(j+1 , len(nums)):
  8. if (nums[i] + nums[j] + nums[z]) == 0:
  9. listMid = [nums[i],nums[j],nums[z]]
  10. if self.isHas(list,listMid):
  11. list.append(listMid)
  12. return list
  13. def isHas(self,list:List[List[int]],check:List[int]) -> bool:
  14. if len(list) == 0:
  15. return True
  16. check = np.sort(np.array(check))
  17. for i in range(len(list)):
  18. listMid = np.sort(np.array(list[i]))
  19. if (listMid == check).all():
  20. return False
  21. return True

排序+双指针法*

Date: 2020-9-24 周四
image.png

  1. class Solution:
  2. def threeSum(self, nums: List[int]) -> List[List[int]]:
  3. n = len(nums)
  4. nums.sort()
  5. ans = list()
  6. # 枚举 a
  7. for first in range(n):
  8. # 需要和上一次枚举的数不相同
  9. if first > 0 and nums[first] == nums[first - 1]:
  10. continue
  11. # c 对应的指针初始指向数组的最右端
  12. third = n - 1
  13. target = -nums[first]
  14. # 枚举 b
  15. for second in range(first + 1, n):
  16. # 需要和上一次枚举的数不相同
  17. if second > first + 1 and nums[second] == nums[second - 1]:
  18. continue
  19. # 需要保证 b 的指针在 c 的指针的左侧
  20. while second < third and nums[second] + nums[third] > target:
  21. third -= 1
  22. # 如果指针重合,随着 b 后续的增加
  23. # 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
  24. if second == third:
  25. break
  26. if nums[second] + nums[third] == target:
  27. ans.append([nums[first], nums[second], nums[third]])
  28. return ans

最接近的三数之和

Date: 2020-9-24 周四
image.png

双指针+排序

  1. class Solution:
  2. def threeSumClosest(self, nums: List[int], target: int) -> int:
  3. min = -1
  4. listNum = 0
  5. nums.sort()
  6. for first in range(len(nums)):
  7. third = len(nums) - 1
  8. scecond = first + 1
  9. if min == 0 :
  10. break
  11. while scecond < third:
  12. sum = nums[first] + nums[scecond] + nums[third]
  13. if min == -1 or abs(sum - target) < min:
  14. min = abs(sum - target)
  15. listNum = sum
  16. if (sum - target) > 0:
  17. third -= 1
  18. else:
  19. scecond += 1
  20. return listNum

电话号码的字母组合**

Date:2020-9-25 周五
image.png

回溯

image.png
image.pngimage.pngimage.pngimage.pngimage.pngimage.png

  1. class Solution:
  2. def letterCombinations(self, digits: str) -> List[str]:
  3. if not digits:
  4. return list()
  5. phoneMap = {"2":"abc","3":"def","4":"ghi","5":"jkl","6":"mno","7":"pqrs","8":"tuv","9":"wxyz"}
  6. def backtrack(index:int):
  7. if index == len(digits):
  8. combinations.append("".join(comination))
  9. else:
  10. digit = digits[index]
  11. for letter in phoneMap[digit]:
  12. comination.append(letter)
  13. backtrack(index+1)
  14. comination.pop()
  15. comination = list()
  16. combinations = list()
  17. backtrack(0)
  18. return combinations

image.png

  1. class Solution:
  2. def letterCombinations(self, digits: str) -> List[str]:
  3. if not digits:
  4. return list()
  5. phoneMap = {"2":"abc","3":"def","4":"ghi","5":"jkl","6":"mno","7":"pqrs","8":"tuv","9":"wxyz"}
  6. groups = (phoneMap[digit] for digit in digits) #生成Generator(生成器)类型
  7. return ["".join(combination) for combination in itertools.product(*groups)] #product 类似于求多个可迭代对象的笛卡尔积 join将list元素拼接成字符串

四数之和

Date:2020-9-25 周五
image.png

双层循环+双指针

  1. class Solution:
  2. def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
  3. nums.sort()
  4. numsLen = len(nums)
  5. result = []
  6. for i in range(numsLen-3):
  7. for j in range(i + 1,numsLen-2):
  8. right = numsLen - 1
  9. left = j + 1
  10. while left < right:
  11. sum = nums[i] + nums[j] + nums[left] +nums[right]
  12. if sum == target:
  13. resultMid = [nums[i] , nums[j] , nums[left] , nums[right]]
  14. if self.checkedList(result,resultMid):
  15. result.append(resultMid)
  16. while nums[right] == nums[right-1] and left < right:
  17. right -= 1
  18. while nums[left] == nums[left+1] and left < right:
  19. left += 1
  20. right -= 1
  21. left += 1
  22. elif sum > target:
  23. right -= 1
  24. else:
  25. left += 1
  26. return result
  27. def checkedList(self,result:List[List[int]],check:List[int]) -> bool:
  28. for i in range(len(result)):
  29. if result[i] == check:
  30. return False
  31. return True

删除链表的倒数第N个节点

Date:2020-9-25 周五
image.png

一次遍历法(双指针)

  1. class Solution:
  2. def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
  3. if head.next == None and n>=1:
  4. return None
  5. headNode = head
  6. endNode = headNode
  7. startNode = None
  8. for _ in range(n):
  9. endNode = endNode.next
  10. if endNode == None and startNode == None:
  11. return headNode.next
  12. else:
  13. while endNode != None:
  14. endNode = endNode.next
  15. if startNode == None:
  16. startNode = headNode
  17. else:
  18. startNode = startNode.next
  19. startNode.next = startNode.next.next
  20. return headNode

合并两个有序链表

Date:2020-9-25 周五
image.png

  1. class Solution:
  2. def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
  3. if l1 == None and l2 == None:
  4. return l1
  5. elif l1 == None:
  6. return l2
  7. elif l2 == None:
  8. return l1
  9. resultListNode = None
  10. result = None
  11. l1Node = l1
  12. l2Node = l2
  13. while l1Node != None and l2Node != None:
  14. if l1Node.val <= l2Node.val:
  15. node = l1Node
  16. l1Node = l1Node.next
  17. node.next = None
  18. if resultListNode == None:
  19. resultListNode = node
  20. result = resultListNode
  21. else:
  22. resultListNode.next = node
  23. resultListNode = resultListNode.next
  24. else:
  25. node = l2Node
  26. l2Node = l2Node.next
  27. node.next = None
  28. if resultListNode == None:
  29. resultListNode = node
  30. result = resultListNode
  31. else:
  32. resultListNode.next = node
  33. resultListNode = resultListNode.next
  34. if l1Node!=None:
  35. if resultListNode == None:
  36. resultListNode = l1Node
  37. result = resultListNode
  38. else:
  39. resultListNode.next = l1Node
  40. resultListNode = resultListNode.next
  41. if l2Node!=None:
  42. if resultListNode == None:
  43. resultListNode = l2Node
  44. result = resultListNode
  45. else:
  46. resultListNode.next = l2Node
  47. resultListNode = resultListNode.next
  48. return result

或者:

  1. class Solution:
  2. def mergeTwoLists(self, l1, l2):
  3. prehead = ListNode(-1)
  4. prev = prehead
  5. while l1 and l2:
  6. if l1.val <= l2.val:
  7. prev.next = l1
  8. l1 = l1.next
  9. else:
  10. prev.next = l2
  11. l2 = l2.next
  12. prev = prev.next
  13. # 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
  14. prev.next = l1 if l1 is not None else l2
  15. return prehead.next

括号生成**

Date:2020-9-28 周一
image.png

暴力

image.png

  1. class Solution:
  2. def generateParenthesis(self, n: int) -> List[str]:
  3. def generate(A):
  4. if len(A) == 2 * n:
  5. if valid(A):
  6. ans.append("".join(A))
  7. else:
  8. A.append("(")
  9. generate(A)
  10. A.pop()
  11. A.append(")")
  12. generate(A)
  13. A.pop()
  14. def valid(A):
  15. bal = 0
  16. for c in A:
  17. if c == "(":bal += 1
  18. else: bal -= 1
  19. if bal < 0:return False
  20. return bal == 0
  21. ans = []
  22. generate([])
  23. return ans

image.png

回溯法

image.png

  1. class Solution:
  2. def generateParenthesis(self, n: int) -> List[str]:
  3. ans = []
  4. def backtrack(S, left, right):
  5. if len(S) == 2 * n:
  6. ans.append(''.join(S))
  7. return
  8. if left < n:
  9. S.append('(')
  10. backtrack(S, left+1, right)
  11. S.pop()
  12. if right < left:
  13. S.append(')')
  14. backtrack(S, left, right+1)
  15. S.pop()
  16. backtrack([], 0, 0)
  17. return ans

image.png

按括号序列的长度递归

image.png

  1. class Solution:
  2. @lru_cache(None)#lru_cache使用了LRU算法,在maxsize=None大小的空间内缓存函数的结果
  3. def generateParenthesis(self, n: int) -> List[str]:
  4. if n == 0:
  5. return ['']
  6. ans = []
  7. for c in range(n):
  8. for left in self.generateParenthesis(c):
  9. for right in self.generateParenthesis(n-1-c):
  10. ans.append('({}){}'.format(left, right))
  11. return ans

image.png

合并K个升序链表

Date:2020-9-29 周二
image.png

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, val=0, next=None):
  4. # self.val = val
  5. # self.next = next
  6. class Solution:
  7. def mergeKLists(self, lists: List[ListNode]) -> ListNode:
  8. nodeList = []
  9. for i in range(len(lists)):
  10. node = lists[i]
  11. while node!=None:
  12. nodeList.append(node.val)
  13. node = node.next
  14. nodeList.sort()
  15. node = ListNode(-1)
  16. indexNode = node
  17. for value in nodeList:
  18. indexNode.next = ListNode(value)
  19. indexNode = indexNode.next
  20. return node.next

思路就是先把列表中的所有链表的值放到一个List中,然后排序在生成一条升序链表。返回即可。

两两交换链表中的节点

Date:2020-9-29 周二
image.png

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def swapPairs(self, head: ListNode) -> ListNode:
  8. if head == None:
  9. return None
  10. index = 0
  11. start = ListNode(-1)
  12. start.next = head
  13. result = start
  14. while start.next != None:
  15. if index % 2 == 0 and start.next.next != None:
  16. left = start.next
  17. right = left.next
  18. left.next = right.next
  19. right.next = left
  20. start.next = right
  21. start = start.next
  22. index +=1
  23. return result.next

K个一组翻转链表

Date:2020-9-29 周二
image.png

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
  8. if head == None:
  9. return None
  10. listLen = 0
  11. nodeList = []
  12. start = ListNode(-1)
  13. start.next = head
  14. nodeIndex = head
  15. while nodeIndex != None:
  16. listLen += 1
  17. nodeIndex = nodeIndex.next
  18. for _ in range(int(listLen / k)):
  19. listMid = []
  20. for _ in range(k):
  21. node = start.next
  22. start.next = node.next
  23. listMid.append(node)
  24. nodeList.append(listMid)
  25. lastNodeList = start.next
  26. reuslt =start
  27. for i in range(int(listLen / k)):
  28. index = k - 1
  29. while index >= 0:
  30. node = nodeList[i][index]
  31. node.next = None
  32. start.next = node
  33. start = start.next
  34. index -=1
  35. start.next = lastNodeList
  36. return reuslt.next

两数相除

Date:2020-9-29 周二
image.png

暴力

  1. class Solution:
  2. def divide(self, dividend: int, divisor: int) -> int:
  3. if dividend == 0: return 0
  4. num = 0
  5. symbols = 0 #0代表负数 1代表正数
  6. if (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0) :
  7. symbols = 1
  8. dividend = abs(dividend)
  9. divisor = abs(divisor)
  10. index = divisor
  11. while index <= dividend:
  12. num += 1
  13. index +=divisor
  14. if dividend > 2**31 -1:
  15. if symbols == 1:
  16. dividend = 2**31 -1
  17. else:
  18. dividend = 2**31
  19. return num if symbols == 1 else -num

暴力虽然可行,但是会导致超时

他人的思路

image.png

  1. class Solution:
  2. def divide(self, dividend: int, divisor: int) -> int:
  3. def recursion(dividend, divisor):
  4. if dividend < divisor:
  5. return 0
  6. if dividend == divisor:
  7. return 1
  8. nn = 1
  9. dd = divisor
  10. while True:
  11. if dividend > dd:
  12. n = nn
  13. nn += nn
  14. d = dd
  15. dd += dd
  16. elif dividend == dd:
  17. return nn
  18. else:
  19. return n + recursion(dividend-d, divisor)
  20. if dividend >= 0:
  21. if divisor > 0:
  22. positive = True
  23. else:
  24. positive = False
  25. else:
  26. if divisor > 0:
  27. positive = False
  28. else:
  29. positive = True
  30. ans = recursion(abs(dividend), abs(divisor))
  31. if positive:
  32. if ans > 2**31 -1:
  33. return 2**31 -1
  34. else:
  35. return ans
  36. else:
  37. return -ans

串联所有单词的子串**

Date:2020-9-29 周二
image.png

我的思路(错误)

最开始我的思路是先把字母列表排列组合,并且去重后得到所有可能的字母组合。然后逐个看是否在字符串S中出现过,通过他出现的次数进行处理。但是Python的字符串的count方法会有问题,比如在“aaa”中“aa”出现的次数是多少次?应该是2次,但是count返回的是1次。就直接导致我的整个方法崩塌掉。其实如果手动实现count方法的话估计也能pass,但是时间复杂度上肯定不如自带函数好用。可惜了

#错误代码
class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        wordsList = []
        resultList = []
        for i in itertools.permutations(words,len(words)): #排列组合字母
            wordsList.append("".join(list(i)))
        wordsList = set(wordsList)
        wordsList = list(wordsList)

        if len(set(s)) == 1 and len(set(wordsList[0])) == 1: #处理aaaaaa的情况
            print(len(words)-len(wordsList))
            for i in range(len(s)-len(wordsList[0])+ 1):
                resultList.append(i)
            return resultList
        for i in range(len(wordsList)):
            if wordsList[i] in s:
                if s.count(wordsList[i]) == 1:
                    # print("==1 :%d"%s.find(wordsList[i]))
                    resultList.append(s.find(wordsList[i]))
                else:
                    sIndex = s
                    # count = 0
                    move = 0
                    while sIndex.count(wordsList[i]) !=0:
                        print("wordsList[i]:%s"%wordsList[i])
                        index = sIndex.find(wordsList[i])
                        # print("index:%d count%d"%(index,count))
                        resultList.append(move + index)
                        # print("find index:%d"%(index + len(wordsList[i])*count))
                        sIndex = sIndex[index + len(wordsList[i]):]
                        move += index + len(wordsList[i])
                        print("move:%d"%move)
                        # count += 1
                        print(sIndex)
        resultList = set(resultList)
        resultList = list(resultList)
        return resultList

别人的思路

image.png
image.png

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        from collections import Counter
        if not s or not words:return []
        one_word = len(words[0])
        all_len = len(words) * one_word
        n = len(s)
        words = Counter(words)
        res = []
        for i in range(0, n - all_len + 1):
            tmp = s[i:i+all_len]
            c_tmp = []
            for j in range(0, all_len, one_word):
                c_tmp.append(tmp[j:j+one_word])
            if Counter(c_tmp) == words:
                res.append(i)
        return res

下一个排列*

Date:2020-9-30 周三
image.png

class Solution:
    def changeList(self,nums:List[int],left:int,right:int):
        mid = nums[left]
        nums[left] = nums[right]
        nums[right] = mid
    def nextPermutation(self, nums: List[int]) -> None:
        index = len(nums) - 1
        while index >= 1: #从后向前查看逆序区域
            if nums[index] > nums[index - 1]:
                break
            index -= 1        
        if index == 0: #倒序
            nums.sort()
        elif index == len(nums) - 1: #正序
            self.changeList(nums,index - 1,index)
        else:
            head = index - 1 #找到逆序区域的前一位,也就是数字置换的边界
            i = len(nums) - 1
            while i > index:
                if nums[i] > nums[head]:
                    break
                i -= 1
            self.changeList(nums,head,i) #把逆序区域的前一位和逆序区域中刚刚大于它的数字交换位置
            i = head + 1
            j = len(nums) - 1
            while i < j: #把原来的逆序区域转为顺序
                self.changeList(nums,i,j)
                i +=1
                j -=1

字典序

这个题需要先搞懂什么是字典序,也可以称为换位数。
image.png
要想获得最近换位数的核心思想是:
image.png

最长有效括号**

Date:2020-9-30 周三
image.png
这道题感觉难在求连续子串的长度。如果是单纯求总共有多少个括号可以匹配比较容易。
看一下大佬的思路:
image.png

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        if not s: return 0

        stack = []
        ans = 0
        for i in range(len(s)):
            # 入栈条件
            if not stack or s[i] == '(' or s[stack[-1]] == ')':
                stack.append(i)     # 下标入栈
            else:
                # 计算结果
                stack.pop()
                ans = max(ans, i - (stack[-1] if stack else -1))
        return ans

搜索旋转排序数组

Date:2020-9-30 周三
image.png

眼瞎没看到时间复杂度限制

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        try:
            return nums.index(target)
        except Exception:
            return -1

二分法

image.png

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return -1
        l, r = 0, len(nums) - 1
        while l <= r:
            mid = (l + r) // 2
            if nums[mid] == target:
                return mid
            if nums[0] <= nums[mid]:
                if nums[0] <= target < nums[mid]:
                    r = mid - 1
                else:
                    l = mid + 1
            else:
                if nums[mid] < target <= nums[len(nums) - 1]:
                    l = mid + 1
                else:
                    r = mid - 1
        return -1

在排序数组中查找元素的第一个和最后一个位置

Date:2020-9-30 周三
image.png

二分法

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        start , end = -1 , len(nums)
        left , right = 0, len(nums) - 1  
        while left <= right :
            mid = int((right + left) / 2)
            if nums[mid] == target:
                start = end = mid
                while start!=0 and nums[start - 1] == target :
                    start -= 1
                while end !=(len(nums) - 1) and nums[end + 1] == target :
                    end += 1
                break   
            elif nums[mid] > target:
                right = mid - 1
            else:
                left = mid + 1
        if start != -1:
            return [start,end]
        else:
            return [-1,-1]