LeetCode-算法
- 1. 两数之和
- 2. 两数相加
- 3. 无重复字符的最长子串
- 4. 寻找两个有序数组的中位数
- 5. 最长回文子串
- 6. Z 字形变换
- 7. 整数反转
- 8. 字符串转换整数 (atoi)
- 9. 回文数
- 10. 正则表达式匹配
- 11. 盛最多水的容器
- 12. 整数转罗马数字
- 13. 罗马数字转整数
- 14. 最长公共前缀
- 15. 三数之和
- 16. 最接近的三数之和
- 17. 电话号码的字母组合
- 18. 四数之和
- 19. 删除链表的倒数第N个节点
- 20. 有效的括号
- 21. 合并两个有序链表
- 22. 括号生成
- 23. 合并K个排序链表
- 24. 两两交换链表中的节点
- 25. K 个一组翻转链表
- 26. 删除排序数组中的重复项
- 27. 移除元素
- 28. 实现 strStr()
- 29. 两数相除
- 30. 串联所有单词的子串
- 31. 下一个排列
- 32. 最长有效括号
- 33. 搜索旋转排序数组
- 34. 在排序数组中查找元素的第一个和最后一个位置
- 35. 搜索插入位置
- 36. 有效的数独
- 37. 解数独
- 38. 外观数列
- 39. 组合总和
- 40. 组合总和 II
- 41. 缺失的第一个正数
- 42. 接雨水
- 43. 字符串相乘
- 44. 通配符匹配
- 45. 跳跃游戏 II
- 46. 全排列
- 47. 全排列 II
- 48. 旋转图像
- 49. 字母异位词分组
- 50. Pow(x, n)
1. 两数之和
nums = [3,2,4, 3]
target = 6
思路
暴力遍历:两个循环遍历所有可能找到答案
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
nums_len = len(nums)
for i in range(nums_len):
for j in range(i+1, nums_len):
if nums[i] + nums[j] == target:
return i, j
思路
遍历第一个数, target减去第一个数得到第二个数的值。利用nums.index()得到第二个数在数组中的索引
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
nums_len = len(nums)
for i in range(nums_len):
if target - nums[i] in nums and i != nums.index(target-nums[i]):
return i, nums.index(target-nums[i])
2. 两数相加
l1 = ListNode(2)
l1.next = ListNode(4)
l1.next.next = ListNode(3)
l2 = ListNode(5)
l2.next = ListNode(6)
l2.next.next = ListNode(4)
# 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
"""
ans = ListNode(0)
r = ans
carry = 0
while (l1 or l2):
x = l1.val if l1 else 0
y = l2.val if l2 else 0
s = carry + x + y
carry = s // 10 # 进位
r.next = ListNode(s%10) # 将节点链接起来
r = r.next
if l1:
l1 = l1.next
if l2:
l2 = l2.next
if carry > 0:
r.next = ListNode(1)
return ans.next
3. 无重复字符的最长子串
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
ans = []
maxlen = 0
i = 0
j = 0
s_len = len(s)
if s_len:
while i < s_len:
if s[i] in ans:
j = ans.index(s[i]) + 1 # s[i]在ans出现重复字符,获取ans被重复字符的位置+1
ans = ans[j:] # 保留重复字符后面的字符
ans.append(s[i])
i = i + 1
else:
ans.append(s[i])
i += 1
if len(ans) > maxlen:
maxlen = len(ans)
else:
maxlen = 0
return maxlen
4. 寻找两个有序数组的中位数
思路
两个序列分别一个个取,计数+1,直到取到中间的数就停止
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
len1 = len(nums1)
len2 = len(nums2)
len3 = len1 + len2
nums3 = []
mid = int((len3) / 2)
count = 0
while count <= mid:
if nums1 and nums2:
if nums1[0] <= nums2[0]:
nums3.append(nums1[0])
nums1 = nums1[1:]
count += 1
else:
nums3.append(nums2[0])
nums2 = nums2[1:]
count += 1
elif nums1:
nums3.append(nums1[0])
nums1 = nums1[1:]
count += 1
elif nums2:
nums3.append(nums2[0])
nums2 = nums2[1:]
count += 1
if len3 % 2 == 0:
ans = (nums3[-1] + nums3[-2])/2.0
else:
ans = float(nums3[-1])
return ans
5. 最长回文子串
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
def preProcess(s):
ret = ""
for i in range(len(s)):
ret = ret + "#"+s[i]
return "^"+ret+"#$"
P = []
ret = preProcess(s) # 添加开始、结束和分隔符,使字符串始终为奇数
n = len(ret)
C, R = 0, 0 # 中心和右边界
for i in range(n - 1):
i_mirror = 2 * C - i
if R > i:
P.append(min(R - i, P[i_mirror]))
else: # i等于右边界
P.append(0)
# 中心扩展法
while ret[i+P[i]+1] == ret[i-P[i]-1]:
P[i] += 1
# 更新R
if (i + P[i]) > R:
C = i
R = i + P[i]
maxlen = 0
centerIndex = 0
for i in range(n - 1):
if P[i] > maxlen:
maxlen = P[i]
centerIndex = i
start = int((centerIndex - maxlen) / 2)
return s[start:start + maxlen]
6. Z 字形变换
class Solution(object):
def convert(self, s, numRows):
"""
:type s: str
:type numRows: int
:rtype: str
"""
n = len(s)
if numRows < 2:
return s
ret = ["" for _ in range(numRows)] # 保存N字字符
flag = -1 # 方向 1:down -1: up
i = 0
for c in s:
ret[i] += c
if i == 0 or i == numRows - 1:
flag = -flag
i += flag
return "".join(ret)
7. 整数反转
class Solution(object):
def reverse(self, x):
"""
:type x: int
:rtype: int
"""
y = 0
flag = 0
if x >= -9 and x <= 9:
y = x
else:
if x < 0:
x = abs(x)
flag = 1
while x > 0:
y = 10*y + x % 10
if y > 2**31 or y < -2**31:
return 0
x //= 10
if flag:
y = -y
return y
8. 字符串转换整数 (atoi)
class Solution(object):
def myAtoi(self, str):
"""
:type str: str
:rtype: int
"""
str1 = str.strip()
ans = ""
for i, c in enumerate(str1):
if (i == 0 and c == '-') or (i == 0 and c == '+') or c.isdigit():
ans += c
else:
break
if ans == "" or ans == "-" or ans == "+":
return 0
else:
ans = int(ans)
if ans > 2**31 -1:
return 2**31 -1
elif ans < -2**31:
return -2**31
else:
return ans
9. 回文数
class Solution(object):
def isPalindrome(self, x):
"""
:type x: int
:rtype: bool
"""
ans = x
y = 0
if x < 0:
return False
else:
if ans == 0:
y = 0
else:
while ans > 0:
y = y * 10 + ans % 10
ans //= 10
if y == x:
return True
else:
return False
10. 正则表达式匹配
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
s_len = len(s)
p_len = len(p)
sp = [[False] * (p_len + 1) for _ in range(s_len + 1)]
sp[-1][-1] = True
for i in range(s_len, -1, -1):
for j in range(p_len - 1, -1, -1):
match = i < s_len and p[j] in {s[i], '.'}
if j + 1 < p_len and p[j+1] == '*':
sp[i][j] = sp[i][j+2] or match and sp[i+1][j]
else:
sp[i][j] = match and sp[i+1][j+1]
return sp[0][0]
11. 盛最多水的容器
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
Hlen = len(height)
l = 0
r = Hlen - 1
maxarea = 0
while l<r:
w = r - l
if height[l]< height[r]:
h = height[l]
l += 1
else:
h = height[r]
r -= 1
area = w * h
maxarea = area if area > maxarea else maxarea
return maxarea
12. 整数转罗马数字
思路
贪心法
class Solution(object):
def intToRoman(self, num):
"""
:type num: int
:rtype: str
"""
roman = [ 'M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I']
nums = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
ans = ''
while num:
for i, v in enumerate(nums):
temp = num//v # 除以包含的数转化为罗马数字
if temp:
num -= (temp)*v
for _ in range(temp):
ans += roman[i]
return ans
13. 罗马数字转整数
思路
倒序输出s,如果当前字符比前一个字符小,减去当前字符对应的数字
class Solution(object):
def romanToInt(self, s):
"""
:type s: str
:rtype: int
"""
roman = {'I':1,'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
ans = 0
pre = 0 # 前一个数
for i in reversed(s):
cur = roman[i] # 当前数
if cur >= pre:
ans += cur
else:
ans -= cur
pre = cur
return ans
14. 最长公共前缀
思路
拿第一个字符作为标准,从头到尾的每个字符与后面的字符串中的字符做比较,全部相同则添加到前缀中
class Solution(object):
def longestCommonPrefix(self, strs):
"""
:type strs: List[str]
:rtype: str
"""
strslen = len(strs)
prestr = ""
flag = 1
if strs:
first = strs[0]
firlen = len(first)
for j in range(firlen):
c = strs[0][j]
for i in range(1, strslen):
if j >= len(strs[i]) or strs[i][j] != c:
flag = 0
break
else:
pass
if flag:
prestr += c
else:
break
return prestr
15. 三数之和
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nlen = len(nums)
nums.sort() # 对数组排序
ans = list()
i = 0
if nlen < 3: # 长度少于3,返回[]
return ans
while i < nlen - 2: # 遍历每个数
cur = nums[i]
if cur > 0:
return ans # 第一个数大于0,返回结果
l = i + 1
r = nlen - 1
while l < r:
if cur + nums[l] + nums[r] < 0: # 三个数相加小于0,l往后移动
l += 1
elif cur + nums[l] + nums[r] > 0: # 三个数相加大于0,r往前移动
r -= 1
else:
if nums[l] == nums[r]: # 两边遇到相同的数,得到答案就可以break掉
ans.append([cur, nums[l], nums[r]])
break
while nums[l] == nums[l+1] and l + 1 < r: # 跳过左边重复的数
l += 1
while nums[r] == nums[r-1] and r - 1 >l: # 跳过右边重复的数
r -= 1
ans.append([cur, nums[l], nums[r]])
l += 1
r -= 1
while nums[i] == nums[i+1] and i + 1 < nlen - 2: # 第一个数重复时,跳过
i += 1
i += 1
return ans
16. 最接近的三数之和
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
i, s, ans = 0, 0, 0
nlen = len(nums)
nums.sort() # 对数组进行排序
distance = sys.maxsize # 距离target的大小,默认给最大值
if nlen<3:
return ans
while i < nlen - 2:
cur = nums[i]
l = i + 1
r = nlen - 1
while l < r: # 寻找第二、三个数
s = cur + nums[l] + nums[r]
temp = abs(s - target)
if temp < distance:
distance = temp
ans = s
if s < 0:
l += 1
else:
r -= 1
i += 1
return ans
17. 电话号码的字母组合
class Solution(object):
def letterCombinations(self, digits):
"""
:type digits: str
:rtype: List[str]
"""
KEY = {'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']}
if not digits:
return []
ans = ['']
for num in digits:
ans = [pre+cur for pre in ans for cur in KEY[num]]
return ans
18. 四数之和
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
nums.sort()
nlen = len(nums)
ans = list()
i = 0
if nlen < 4:
return ans
while i < nlen - 3: # 遍历第一个数
j = i + 1
while j < nlen - 2: # 遍历第二个数
l = j + 1
r = nlen - 1
while l < r: # 寻找第三、四个数
if nums[i] + nums[j] + nums[l] + nums[r] < target and l < r: # 总和比target小,l往右移动
l += 1
elif nums[i] + nums[j] + nums[l] + nums[r] > target and l < r: # 总和比target大,r往右移动
r -= 1
else:
if nums[l] == nums[r]: # 总和相等时,第三、四个数相同,终止遍历
ans.append([nums[i], nums[j], nums[l], nums[r]])
break
while nums[l] == nums[l+1] and l+1 < r: # 第三个数重复,跳过
l += 1
while nums[r] == nums[r-1] and r-1 > l: # 第四个数重复,跳过
r -= 1
ans.append([nums[i], nums[j], nums[l], nums[r]])
l += 1
r -= 1
while nums[j] == nums[j+1] and j + 1 < nlen - 2: # 第二个数重复,跳过
j += 1
j += 1
while nums[i] == nums[i+1] and i + 1 < nlen - 3: # 第一个数重复,跳过
i += 1
i += 1
return ans
19. 删除链表的倒数第N个节点
head = ListNode(1)
temp = head
for i in range(2, 6):
temp.next = ListNode(i)
temp = temp.next
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
first = head
second = head
if n == 0:
return head
for _ in range(n): # 第一个指针先走n步
if first.next != None:
first = first.next
else: # 走到最后一个数
first = head
# 第一个指针走到末尾,第二个指针跟第一个距离为n,第二个指针指向下下个结点,去除倒数第n个结点
while first.next != None:
first = first.next
second = second.next
if second.next == None: # 删除第一个
second = head
second = second.next
head = second
elif second.next.next == None: # 删除倒数第一个
second.next = None
else:
second.next = second.next.next
return head
20. 有效的括号
思路
- 队列:FIFO=先进先出 LIFO=后入先出
使用LIFO,遍历所有字符,遇到左括号则放进队列里,遇到右括号则将左括号取出,检查左右括号是否一对,直到队列为空
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
left = list()
if not s:
return True
for c in s:
if c in ['(', '[', '{']:
left.append(c)
else:
if not left:
return False
else:
l = left.pop()
if (l == '(' and c == ')') or (l == '[' and c == ']') or (l == '{' and c == '}'):
pass
else:
return False
if left:
return False
else:
return True
21. 合并两个有序链表
l1 = ListNode(1)
l1.next = ListNode(2)
l1.next.next = ListNode(4)
l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)
思路
两个链表对比大小,把较小的数放在新链表里
# 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
"""
anshead = ListNode(-1)
ans = anshead
while l1 != None and l2 != None:
if l1.val <= l2.val:
ans.next = l1
l1 = l1.next
ans = ans.next
else:
ans.next = l2
l2 = l2.next
ans = ans.next
if l1 != None:
ans.next = l1
elif l2 != None:
ans.next = l2
return anshead.next
思路
递归两个链表
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
if l2 is None:
return l1
elif l1 is None:
return l2
elif l1.val <= l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
22. 括号生成
思路
递归,添加少于n个左括号,右括号少于左括号个数时添加
class Solution(object):
def generateParenthesis(self, n):
"""
:type n: int
:rtype: List[str]
"""
ans = list()
def valid(S='', left=0, right=0):
if len(S) == 2 * n:
ans.append(S)
return ans
if left < n:
valid(S+'(', left+1, right)
if right < left:
valid(S+')', left, right+1)
valid()
return ans
23. 合并K个排序链表
lists = list()
l1 = ListNode(1)
l1.next = ListNode(4)
l1.next.next = ListNode(5)
l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)
l3 = ListNode(2)
l3.next = ListNode(6)
lists.append(l1)
lists.append(l2)
lists.append(l3)
思路
暴力法:将所有数放在一个数组里,再进行排序,再形成链表
# 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
"""
anshead = ListNode(-1)
ans = anshead
llen = len(lists)
nums = list()
for i in range(llen):
l = lists[i]
while l != None:
nums.append(l.val)
l = l.next
nums.sort()
for n in nums:
ans.next = ListNode(n)
ans = ans.next
return anshead.next
24. 两两交换链表中的节点
head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)
思路
递归交换
# 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
"""
def sw(head):
if head == None or head.next == None:
return head
n = head.next
head.next = sw(n.next)
n.next = head
return n
return sw(head)
思路
创建一个头部指向head
# 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
"""
pre = ListNode(-1)
pre.next = head # 1
h = pre
while h.next != None and h.next.next != None:
first = h.next # 2
second = h.next.next # 3
h.next = second # 4
first.next = second.next # 5
second.next = first # 6
h = first # 7
return pre.next
25. K 个一组翻转链表
思路
- 当链表长度大于k时,将k长度的放进列表里(堆),然后进行翻转
- 当链表剩下长度小于k的,直接连接在后面
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
pre = ListNode(-1)
p = pre
while True:
count = k
h = head
temp = list()
while count and h:
temp.append(h)
h = h.next
count -= 1
if count: # 链表长度少于k
p.next = head
break
while temp: # 链表长度大于k时,翻转链表
p.next = temp.pop()
p = p.next
p.next = h
head = h
return pre.next
思路
- 当链表长度大于k时,tail指向第k个数,分别将数字插入到tail后面翻转k个链表
- 当链表剩余长度小于k时,将剩余部分连接起来
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
pre = ListNode(-1)
pre.next = head
p = pre
tail = pre
while True:
count = k
while count and tail:
count -= 1
tail = tail.next
if not tail:
break
head = p.next
while p.next != tail:
cur = p.next
p.next = cur.next
cur.next = tail.next
tail.next = cur
p = head
tail = head
return pre.next
26. 删除排序数组中的重复项
思路
使用set去重,但空间复杂度为O(n),不符合题意
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
temp = list(set(nums))
tlen = len(temp)
temp.sort()
for i in range(tlen):
nums[i] = temp[i]
return tlen
思路
双指针
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nlen = len(nums)
if not nums:
return 0
i = 0
for j in range(1, nlen):
if nums[i] != nums[j]:
i += 1
nums[i] = nums[j]
return i+1
27. 移除元素
思路
将等于val的数字pop掉
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
nlen = len(nums)
i = 0
while i < len(nums):
if nums[i] == val:
nums.pop(i)
continue
i += 1
return len(nums)
思路
双指针:重头到位遍历,保存不等于val的数字
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
nlen = len(nums)
i = 0
for j in range(nlen):
if nums[j] != val:
nums[i] = nums[j]
i += 1
return i
28. 实现 strStr()
思路
显而易见
class Solution(object):
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
return haystack.index(needle) if needle in haystack else -1
29. 两数相除
思路
移位运算:乘(左移);除(右移),一位是2
class Solution(object):
def divide(self, dividend, divisor):
"""
:type dividend: int
:type divisor: int
:rtype: int
"""
sign = (dividend > 0) ^ (divisor > 0)
dividend = abs(dividend)
divisor = abs(divisor)
count = 0
while dividend >= divisor:
count += 1
divisor <<= 1 # 左移,每次乘以2,知道大于被除数
ans = 0
while count:
count -= 1
divisor >>= 1
if divisor <= dividend:
ans += 1<<count # 左移将二进制转为十进制
dividend -= divisor
if sign:
ans = -ans
return ans if -(1<<31) <= ans <= (1<<31)-1 else (1<<31)-1
30. 串联所有单词的子串
思路
- 在s截取words总长度的stemp,遍历stemp将长度为word的字符,添加至temp里
- words,temp的字符和出现次数形成哈希表,两者相等则返回起始下标i
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
from collections import Counter
ans = list()
if not s or not words:
return ans
wlen = len(words[0])
wslen = len(words) * wlen
slen = len(s)
words = Counter(words)
for i in range(slen - wslen + 1):
stemp = s[i:i+wslen]
temp = list()
for j in range(0, wslen, wlen):
temp.append(stemp[j:j+wlen])
if Counter(temp) == words:
ans.append(i)
return ans
31. 下一个排列
思路
- 如果为空数组或长度为1的数组直接返回
- 如果找到数组中前一个小于后一个的数字,下标为i-1(nums[i-1]<nums[i]),否则,前一个均大于后一个数,则为最大排列,i==0
- 如果i>0,即nums[i-1]<nums[i],从数组后往前寻找比nums[i-1]稍大的数与nums[i-1]交换
- 由2得出,i-1后面数字为降序排序,头部与尾部对换,使其变为升序排序
class Solution(object):
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
nlen = len(nums)
flag = 0
if nlen == 0 or nlen == 1:
return nums
i = nlen - 1
while i > 0 and nums[i-1] >= nums[i]:
i -= 1
if i > 0: # 数组里前面有小于后面的数
j = nlen - 1
while j > i-1 and nums[j] <= nums[i-1]:
j -= 1
nums[i-1], nums[j] = nums[j], nums[i-1]
start = i
last = nlen-1
while start < last:
nums[start], nums[last] = nums[last], nums[start]
start += 1
last -= 1
return nums
32. 最长有效括号
思路
- 建立长度为字符串s长度的数组,初始化为0
- 遇到右括号时查看前一个字符,如果是左括号,长度加2,如果是右括号,减去前一个括号的连续字符长度再减1,查看是否左括号与其对应,如果是,2(增加的有效括号长度)+dp[i-1](前一个右括号的有效长度)+dp[i-dp[i-1]-2](与当前右括号对应的左括号前一个括号的有效长度)
class Solution(object):
def longestValidParentheses(self, s):
"""
:type s: str
:rtype: int
"""
if not s:
return 0
# 1
slen = len(s)
dp = [0]*slen
for i in range(1, slen):
if s[i] == ')':
if s[i-1] == '(':
dp[i] = dp[i-2] + 2 if i > 2 else 2
elif s[i-1] == ')' and i - dp[i-1] > 0 and s[i-dp[i-1]-1] == '(':
dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
return max(dp)
思路
- 从左往右遍历一次,记下左、右括号数,相等时计算长度,大于最大长度时更新,遇到左括号数小于右括号数时,长度清零,如())(),到第二个右括号时,括号不连续,长度清零
- 从右往左遍历一次,记下左、右括号数,相等时计算长度,大于最大长度时更新,遇到右括号数小于左括号数时,长度清零,如()((),到第二个左括号时,括号不连续,长度清零
class Solution(object):
def longestValidParentheses(self, s):
"""
:type s: str
:rtype: int
"""
if not s:
return 0
slen = len(s)
left, right = 0, 0
maxlen = 0
for i in range(slen):
if s[i] == '(':
left += 1
else:
right += 1
if left == right:
templen = left + right
if templen > maxlen:
maxlen = templen
elif left < right:
templen = 0
left, right = 0, 0
left, right = 0, 0
for j in range(slen-1, -1, -1):
if s[j] == ")":
right += 1
else:
left += 1
if left == right:
templen = left + right
if templen > maxlen:
maxlen = templen
elif right < left:
templen = 0
left, right = 0, 0
return maxlen
33. 搜索旋转排序数组
思路
- 二分查找最小的数为数组有序的分界点
- target小于最小的数返回-1
- target大于等于数组第一个数,则target可能存在数组左边有序序列中,否则target可能存在数组右边有序序列中
- 在有序序列中使用二分查找target
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
# 查找最小的数
def findmin(nums, l, r):
if nums[l] <= nums[r]:
return l
while l <= r:
m = (l+r)//2
if nums[m] > nums[m+1]:
return m+1
else:
if nums[m] > nums[l]:
l = m+1
else:
r = m
# 二分查看
def binary(nums, l, r, target):
while l <= r:
mid = (l+r)//2
if nums[mid] == target:
return mid
elif nums[mid] > target:
r = mid - 1
else:
l = mid + 1
return -1
nlen = len(nums)
l, r = 0, nlen - 1
if not nums:
return -1
if nlen == 1:
return 0 if target == nums[0] else -1
# 1
mini = findmin(nums, l, r)
# mini在第一位,直接使用二分查找
if mini == l:
return binary(nums, l, r, target)
# 2
if target < nums[mini]:
return -1
# 3 4
if target >= nums[l]:
return binary(nums, l, mini-1, target)
else:
return binary(nums, mini, r, target)
思路
O(∩_∩)O哈哈~
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
return nums.index(target) if target in nums else -1
34. 在排序数组中查找元素的第一个和最后一个位置
思路
- 二分查找target
- 往左和右边寻找相同的数,移动下标
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
if not nums:
return [-1, -1]
def binary(nums, l, r, target):
while l <= r:
m = (l+r)//2
if nums[m] == target:
return m
elif nums[m] > target:
r = m - 1
else:
l = m + 1
return -1
nlen = len(nums)
l, r = 0, nlen - 1
# 1
index = binary(nums, l, r, target)
start,end = index, index
# 2
if index != -1: # target存在数组中
while start-1 >= l and nums[start-1] == nums[start]:
start -= 1
while end+1 <= r and nums[end+1] == nums[end]:
end += 1
return [start, end]
35. 搜索插入位置
思路
二分查找,找到target返回下标,找不到返回l的位置即为插入位置
class Solution(object):
def searchInsert(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if not nums:
return 0
nlen = len(nums)
l, r = 0, nlen - 1
while l <= r:
m = (l+r)//2
if nums[m] == target:
return m
elif nums[m] > target:
r = m - 1
else:
l = m + 1
return l
36. 有效的数独
board = [
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
思路
行、列、小矩阵遍历是否有重复的数,如果已经存在,即返回False;遍历结束,没有相同即返回True
确定小矩阵index
i | j | box_idx |
---|---|---|
0-2 | 0-2 | 0 |
0-2 | 3-5 | 1 |
0-2 | 6-8 | 2 |
3-5 | 0-2 | 3 |
3-5 | 3-5 | 4 |
3-5 | 6-8 | 5 |
6-8 | 0-2 | 6 |
6-8 | 3-5 | 7 |
6-8 | 6-8 | 8 |
由此可得:box_idx = (i//3)*3+j//3
class Solution(object):
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
rows = [[] for _ in range(9)]
columns = [[] for _ in range(9)]
boxes = [[] for _ in range(9)]
for i in range(9):
for j in range(9):
num = board[i][j]
if board[i][j] != '.':
box_idx = (i//3)*3+j//3
if num not in rows[i] and num not in columns[j] and num not in boxes[box_idx]:
rows[i].append(num)
columns[j].append(num)
boxes[box_idx].append(num)
else:
return False
return True
37. 解数独
board = [
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
思路
- 建立数组行、列、小方格,将已有的数字,对应的下标设为1,没有的数字设置为0
- 回溯法
class Solution(object):
def solveSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""
def delnum(num, i, j):
rows[i][num] = 0
columns[j][num] = 0
box_id = (i//3)*3+j//3
boxes[box_id][num] = 0
def fillnum(num, i, j):
rows[i][num] += 1
columns[j][num] += 1
box_id = (i//3)*3+j//3
boxes[box_id][num] += 1
def solve(row, col):
if row == 9 and col == 0: # 回溯结束的条件
return True
if board[row][col] == '.':
box_id = (row//3)*3+col//3
for num in range(1, 10):
if rows[row][num]==0 and columns[col][num]==0 and boxes[box_id][num]==0:
fillnum(num, row, col)
board[row][col] = str(num)
ans = solve(row+1, 0) if col == 8 else solve(row, col+1)
if ans:
return True
if not ans: # 回溯时清除已填的错误数字
delnum(int(num), row, col)
board[row][col] = '.'
else:
ans = solve(row+1, 0) if col == 8 else solve(row, col+1)
if ans:
return True
# 1
rows = [[0 for _ in range(10)] for _ in range(9)]
columns = [[0 for _ in range(10)] for _ in range(9)]
boxes = [[0 for _ in range(10)] for _ in range(9)]
for i in range(9):
for j in range(9):
if board[i][j] != '.':
fillnum(int(board[i][j]), i, j)
# 2
solve(0, 0)
return board
38. 外观数列
思路
递归:上一次得到的结果作为输入
class Solution(object):
def countAndSay(self, n):
"""
:type n: int
:rtype: str
"""
if n == 1:
return "1"
nums = self.countAndSay(n-1) # 上一次得到的结果作为输入
nlen = len(nums)
count = 1
re = ""
for i in range(nlen-1):
if nums[i] == nums[i+1]:
count += 1
else:
re = re + str(count) + nums[i]
count = 1
re = re + str(count) + nums[nlen-1]
return re
39. 组合总和
思路
回溯
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
candidates.sort()
clen = len(candidates)
ans = list()
def solve(index, sub, sumn):
if sumn == target:
ans.append(sub)
return
if sumn > target or index == clen:
return
if sumn+candidates[index] <= target: # 剪枝
solve(index, sub+[candidates[index]], sumn+candidates[index])
solve(index+1, sub, sumn)
solve(0, [], 0)
return ans
40. 组合总和 II
思路
回溯
class Solution(object):
def combinationSum2(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
candidates.sort()
clen = len(candidates)
ans = list()
def solve(index, sub, sumn):
if sumn == target:
if sub not in ans: # 去重
ans.append(sub)
return
if sumn > target or index == clen:
return
if sumn + candidates[index] <= target: # 剪枝
solve(index + 1, sub + [candidates[index]], sumn + candidates[index]) # 加上当前值,并把索引指向下一个数字
solve(index + 1, sub, sumn)
solve(0, [], 0)
return ans
41. 缺失的第一个正数
思路
根据数组长度去寻找没有出现在数字中的正整数
class Solution(object):
def firstMissingPositive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nlen = len(nums)
if not nlen:
return 1
for i in range(1, nlen+1):
if i not in nums:
return i
return nlen + 1
42. 接雨水
思路
双指针:
- 下标分别指向最左侧l和最右侧r
- 分别保存左边和右边最高的数字(柱子)left_max, right_max
- 左侧柱子小于右侧柱子时,左侧往右遍历,小于left_max时,left_max减去当前柱子高度,累加到ans中
- 右侧柱子小于等于左侧柱子时,右侧往左遍历,小于right_max时,right_max减去当前柱子高度,累加到ans中
- 左右侧下标相遇时,结束遍历,返回ans
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
hlen = len(height)
l, r = 0, hlen - 1
ans = 0
if hlen == 0:
return 0
left_max = height[l]
right_max = height[r]
while l < r:
if height[l] < height[r]:
if height[l] > left_max:
left_max = height[l]
else:
ans += left_max - height[l]
l += 1
else:
if height[r] > right_max:
right_max = height[r]
else:
ans += right_max - height[r]
r -= 1
return ans
43. 字符串相乘
思路
映射为数字
class Solution(object):
def multiply(self, num1, num2):
"""
:type num1: str
:type num2: str
:rtype: str
"""
mapping = {
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9
}
n1len, n2len = len(num1), len(num2)
tmp1, tmp2 = 0, 0
for i in num1:
tmp1 = tmp1*10 + mapping[i]
for j in num2:
tmp2 = tmp2*10 + mapping[j]
return (str(tmp1*tmp2))
44. 通配符匹配
思路
双指针
- s[i]和p[j]匹配,或p[j]==’?’, i/j加1
- p[j]==’*’,标记位置,匹配空字符或j+1与s中寻找匹配的字符
- s匹配结束后,查看p是否有剩余字符,剩余字符是否为*,是为True,否则为False
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
slen, plen = len(s), len(p)
start = -1
match = 0
i, j = 0, 0
while i < slen:
if j < plen and (s[i] == p[j] or p[j] == '?'):
i += 1
j += 1
elif j < plen and p[j] == '*':
start = j
match = i
j += 1
elif start != -1:
j = start +1
match += 1
i = match
else:
return False
return all(x == "*" for x in p[j:])
45. 跳跃游戏 II
思路
step跳跃一次,end等于能到达的最大位置,如果end走到nums最后或大于nums位置,则完成跳跃
class Solution(object):
def jump(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nlen = len(nums)
step = 0
end, maxindex = 0, 0
for i in range(0, nlen-1):
maxindex = max(i + nums[i], maxindex)
if i == end:
step += 1
end = maxindex
if end >= nlen-1:
return step
return step
46. 全排列
思路
- 求所有可能出现在第一个位置的字符,即把第一个字符和后面的所有字符交换
- 然后固定第一个字符,求后面所有字符的排序
- 把后面的字符看成两部分,第一个字符和后面的字符,然后重复上述步骤(递归,归的终止条件是需要处理的字符长度为 1)
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) <= 1:
return [nums]
temp = []
for i in range(len(nums)):
for j in self.permute(nums[0:i]+nums[i+1:]):
temp.append([nums[i]] + j)
return temp
47. 全排列 II
思路
- 求所有可能出现在第一个位置的字符,即把第一个字符和后面的所有字符交换
- 然后固定第一个字符,求后面所有字符的排序
- 把后面的字符看成两部分,第一个字符和后面的字符,然后重复上述步骤(递归,归的终止条件是需要处理的字符长度为 1)
- 剪枝:出现已经作为第一个数的情况就剪枝
class Solution(object):
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) <= 1:
return [nums]
ans = []
first = []
for i in range(len(nums)):
if nums[i] not in first: # 剪枝
first.append(nums[i])
else:
continue
for j in self.permuteUnique(nums[0:i]+nums[i+1:]):
ans.append([nums[i]] + j)
return ans
48. 旋转图像
思路
- 使用数组保存旋转后的数组
- 赋值给原来的数组
class Solution(object):
def rotate(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: None Do not return anything, modify matrix in-place instead.
"""
row = len(matrix)
col = len(matrix[0])
ans = [[] for _ in range(row)]
for i in range(row):
for j in range(col):
ans[i].append(matrix[col-j-1][i])
for i in range(row):
for j in range(col):
matrix[i][j] = ans[i][j]
return matrix
49. 字母异位词分组
思路
创建字典,用sorted辨识字母相同的作为key,对应的词添加到value中
class Solution(object):
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
ans = dict()
for s in strs:
sort_s = sorted(s)
key = ''.join(sort_s)
if key not in ans.keys():
ans[key] = [s]
else:
ans[key].append(s)
return list(ans.values())
50. Pow(x, n)
思路
暴力破解会提示“MemoryError”
- 当
n
n
n为负数时:
x = 1 x x = {1 \over x} x=x1
n = − n n = -n n=−n - 将
n
n
n分解一下:
x n 2 × x n 2 = x n x^{n\over2}\times x^{n\over2}=x^n x2n×x2n=xn - 当
n
n
n为偶数时:
x n 2 = A , x n = A × A x^{n\over2}=A, x^n = A\times A x2n=A,xn=A×A - 当
n
n
n为奇数时:
n n n除以2 得到余数1
x n 2 = A , x n − 1 = A × A x^{n\over2}=A, x^{n-1} = A\times A x2n=A,xn−1=A×A
最后再乘以一个 x x x就行
class Solution(object):
def myPow(self, x, n):
"""
:type x: float
:type n: int
:rtype: float
"""
def halfPow(x,n):
if n == 0:
return 1.0
half = halfPow(x,n//2)
if n%2 == 0:
return half*half
else:
return half*half*x
if n < 0:
x = 1.0/x
n = -n
return halfPow(x, n)