【700】Leecode solution
001. 两数之和
2022年7月12日
【分析】最简单的想法就是两层遍历,时间复杂度为 $O(n^2)$。为了提高效率因此不能进行两层遍历,第一层的遍历是必须的,针对每一个元素,考虑 target-nums[i] 是否在数组里面。因为最终的结果需要索引值,因此考虑到将 nums 的元素作为 key,索引作为 value 来构建 哈希表(字典),从而可以根据数值获取对应的索引值!
【总结】哈希表的灵活使用很重要,特别是涉及到索引的问题,重要函数 hashmap.get(key),如果找到,则返回对应的值,如果找不到,则返回 None。
002. 两数相加
2022年7月13日
【分析】主要是考察链表,根据已经定义好的链表class来直接用。注意不同链表的不同处理情况!
【总结】链表就是逻辑性很强,但是不难
Python实现链表操作
(1)定义 ListNode
查看代码
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
(2)将list转为链表
查看代码
def create_list_node(list1):
"""
把list转为链表
"""
head = ListNode() # 头结点,设置为空
loop_node = head # 循环结点
for e in list1: # 通过循环构建新的结点,并连接起来
tmp_node = ListNode(e)
loop_node.next = tmp_node
loop_node = tmp_node
return head.next # 最终返回头结点的下一个结点即可
(3)将链表转为list
查看代码
def print_list_node(l1):
"""
把链表转为list
"""
arr = []
while l1:
arr.append(l1.val)
l1 = l1.next
return arr
最终代码:
查看代码
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
# 定义一个头结点
l3 = ListNode()
# 定义一个指针
p = l3
# 定义进位值
flag = 0
# 针对不同的情况分别考虑
while l1 != None or l2 != None:
if l1 == None:
s = l2.val + flag
flag = 0
if s > 9:
s = s % 10
flag = 1
l2 = l2.next
elif l2 == None:
s = l1.val + flag
flag = 0
if s > 9:
s = s % 10
flag = 1
l1 = l1.next
else:
s = l1.val + l2.val + flag
flag = 0
if s > 9:
s = s % 10
flag = 1
l1 = l1.next
l2 = l2.next
tmp_node = ListNode(s)
p.next = tmp_node
p = p.next
if flag == 1:
tmp_node = ListNode(1)
p.next = tmp_node
return l3.next
003. 无重复字符的最长子串
查看代码
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
tmp = ""
max_length = 0
for e in s:
if e not in tmp:
tmp += e
else:
ind = tmp.find(e)
tmp = tmp[(ind+1):] + e
if len(tmp) > max_length:
max_length = len(tmp)
return max_length
004. 寻找两个正序数组的中位数
005. 最长回文子串
-
暴力解法:遍历每一个字符,然后两边扩散
-
动态规划:构建二维数组,参考讲解答案
方法一:暴力解法
查看代码
class Solution:
def longestPalindrome(self, s: str) -> str:
max_len = 0
max_str = ""
for i in range(len(s)):
i_r = i
for k in range(1, len(s)-i):
if s[i+k] != s[i]:
i_r = i + k-1
break
if k == len(s) - i - 1:
i_r = len(s)
length = i_r - i + 1
if length > max_len:
max_len = length
max_str = s[i:i_r+1]
for j in range(min(i+1, len(s)-i_r)):
if s[i-j] != s[i_r+j]:
length = 2*j-2 + i_r - i + 1
if length > max_len:
max_len = length
max_str = s[i-j+1:i_r+j]
break
if j == min(i+1, len(s)-i_r) - 1:
length = 2*j + i_r - i + 1
if length > max_len:
max_len = length
max_str = s[i-j:i_r+j+1]
return max_str
方法二:动态规划
查看代码
class Solution:
def longestPalindrome(self, s: str) -> str:
if len(s) == 0: return ""
dp = [[False] * len(s) for i in range(len(s))]
for i in range(len(s)):
dp[i][i] = True
max_len = 1
max_str = s[0]
for j in range(1, len(s)):
for i in range(j):
if s[i] == s[j] and (j-i<3 or dp[i+1][j-1]):
dp[i][j] = True
if j - i + 1 > max_len:
max_len = j - i
max_str = s[i:j+1]
return max_str
006. Z 字形变换
- 分别考虑两种情况,一种是一列上面都是满的,一种情况就是一列只有一个元素
查看代码
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows == 1: return s
arr = [[""] * len(s) for i in range(numRows)]
ind = 0
# 需要注意的是,二维数组是[row][column]形式的,所以赋值的时候
# 注意是arr[j][i],不要弄反了!
for i in range(len(s)):
if ind == len(s): break
# 能整除的列,全部遍历显示
if i % (numRows - 1) == 0:
for j in range(numRows):
if ind == len(s): break
arr[j][i] = s[ind]
ind += 1
if ind == len(s): break
# 不能整除的列,只显示一个位置,通过归纳找到对应的索引值
if i % (numRows - 1) != 0:
if ind == len(s): break
ind_j = numRows - 1 - i % (numRows - 1)
arr[ind_j][i] = s[ind]
ind += 1
if ind == len(s): break
return ''.join([''.join(arr[i]) for i in range(numRows)])
007. 整数反转
-
可以直接通过字符串反转来实现
-
可以通过十进制的规律来获取每一位的数字,再反向组成数字
方法一:
查看代码
class Solution:
def reverse(self, x: int) -> int:
if x==0: return 0
tmp = (x//abs(x)) * int(str(abs(x))[::-1])
if tmp < -2**31 or tmp > 2**31-1:
return 0
return tmp
方法二:
查看代码
class Solution:
def reverse(self, x: int) -> int:
if x==0: return 0
if x > 0: x_tmp = x
if x < 0: x_tmp = -1 * x
num_arr = []
while x_tmp > 0:
num_arr.append(x_tmp % 10)
x_tmp = x_tmp // 10
num = 0
carry = 1
for i in range(len(num_arr)-1, -1, -1):
num += num_arr[i] * carry
carry *= 10
if x < 0: num = -1 * num
if num < -2**31 or num > 2**31-1:
return 0
return num
008. 字符串转换整数 (atoi)
-
主要考虑规则
-
首先去掉前面空格
-
连续的可以作为数字才考虑
-
"+-200-+300" 返回 0
-
代码中使用了try...except...
来完成报错情况的结果输出,整体的代码就是一边调试一边修改,因为对具体的规则不了解!
查看代码
class Solution:
def myAtoi(self, s: str) -> int:
s = s.strip()
if s=="": return 0
ref = ["+", "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
if s[0] not in ref: return 0
s_cut = ""
for i in range(len(s)):
if s[i] not in ref:
s_cut = s[:i]
break
if i == len(s)-1:
s_cut = s
flag = 0
for i in range(len(s_cut)):
if s_cut[i] not in ["+", "-"]:
flag = 1
if flag and s_cut[i] in ["+", "-"]:
s_cut = s_cut[:i]
break
try:
res = int(s_cut)
except:
return 0
if int(s_cut) < -1 * 2 ** 31:
return -1 * 2 ** 31
if int(s_cut) > 2 ** 31 - 1:
return 2 ** 31 - 1
return int(s_cut)
011. 盛最多水的容器
- 可以通过动态规划的思想来解答,但是会超时,动态规划时间复杂度过高
-
通过设置
left
和right
两个指针,然后根据情况进行左右移动,效率更高
查看代码
class Solution:
def maxArea(self, height: List[int]) -> int:
# 时间复杂度过大,无法通过
#dp = [0] * (len(height) + 1)
#dp[2] = min(height)
#for i in range(3, len(height) + 1):
# dp[i] = max(dp[i-1], max([(i-1-j)*min(height[j], height[i-1]) for j in range(i-1)]))
#return dp[-1]
# 下面为双指针方法
left = 0
right = len(height) - 1
maxA = 0
while left < right:
tmp = (right - left) * min(height[left], height[right])
if maxA < tmp: maxA = tmp
if height[left] < height[right]:
left += 1
else:
right -= 1
return maxA
012. 整数转罗马数字
- 利用穷举的方法来实现!
查看代码
class Solution:
def intToRoman(self, num: int) -> str:
res = ""
if num // 3000 > 0:
num %= 3000
res += "MMM"
if num // 2000 > 0:
num %= 2000
res += "MM"
if num // 1000 > 0:
num %= 1000
res += "M"
if num // 900 > 0:
num %= 900
res += "CM"
if num // 500 > 0:
num %= 500
res += "D"
if num // 400 > 0:
num %= 400
res += "CD"
if num // 300 > 0:
num %= 300
res += "CCC"
if num // 200 > 0:
num %= 200
res += "CC"
if num // 100 > 0:
num %= 100
res += "C"
if num // 90 > 0:
num %= 90
res += "XC"
if num // 50 > 0:
num %= 50
res += "L"
if num // 40 > 0:
num %= 40
res += "XL"
if num // 30 > 0:
num %= 30
res += "XXX"
if num // 20 > 0:
num %= 20
res += "XX"
if num // 10 > 0:
num %= 10
res += "X"
if num // 9 > 0:
num %= 9
res += "IX"
if num // 5 > 0:
num %= 5
res += "V"
if num // 4 > 0:
num %= 4
res += "IV"
if num // 3 > 0:
num %= 3
res += "III"
if num // 2 > 0:
num %= 2
res += "II"
if num // 1 > 0:
num %= 1
res += "I"
return res
【分析】最
【总结】哈
15. 三数之和
可以通过双指针的方式来降低时间复杂度!
查看代码
class Solution:
def threeSum( self , nums: List [ int ]) - > List [ List [ int ]]:
arr = []
length = len (nums)
nums.sort()
for i in range (length - 2 ):
if nums[i] > 0 : break
if i > 0 and nums[i] = = nums[i - 1 ]: continue
left = i + 1
right = length - 1
while left < right:
s = nums[i] + nums[left] + nums[right]
if s = = 0 :
arr.append([nums[i], nums[left], nums[right]])
left + = 1
right - = 1
while (left < right and nums[left] = = nums[left - 1 ]): left + = 1
while (left < right and nums[right] = = nums[right + 1 ]): right - = 1
elif s < 0 :
left + = 1
while (left < right and nums[left] = = nums[left - 1 ]): left + = 1
else :
right - = 1
while (left < right and nums[right] = = nums[right + 1 ]): right - = 1
return arr
016. 最接近的三数之和
可以通过双指针的方式来降低时间复杂度!
查看代码
class Solution:
def threeSumClosest( self , nums: List [ int ], target: int ) - > int :
nums.sort()
res = nums[ 0 ] + nums[ 1 ] + nums[ - 1 ]
gap = abs (res - target)
for i in range ( len (nums) - 2 ):
if nums[i] > 0 and nums[i] > target: break
left = i + 1
right = len (nums) - 1
while (left < right):
s = nums[i] + nums[left] + nums[right]
if s = = target:
return target
elif s < target:
if target - s < gap:
gap = target - s
res = s
left + = 1
else :
if s - target < gap:
gap = s - target
res = s
right - = 1
return res
017. 电话号码的字母组合
使用动态规划的方法来解决!
查看代码
class Solution:
def letterCombinations( self , digits: str ) - > List [ str ]:
if not digits: return []
hashmap = { "2" : "abc" , "3" : "def" , "4" : "ghi" , "5" : "jkl" ,
"6" : "mno" , "7" : "pqrs" , "8" : "tuv" , "9" : "wxyz" }
dp = [[] for i in range ( len (digits) + 1 )]
dp[ 1 ] = [e for e in hashmap[digits[ 0 ]]]
for i in range ( 2 , len (digits) + 1 ):
arr = []
for e1 in dp[i - 1 ]:
for e2 in hashmap[digits[i - 1 ]]:
arr.append(e1 + e2)
dp[i] = arr
return dp[ - 1 ]
18. 四数之和
双指针的方法!
367. 有效的完全平方数
解决方案:对于已经排好序的遍历问题,可以优先考虑二分法!
查看代码
class Solution:
def isPerfectSquare(self, num: int) -> bool:
if num == 1: return True
#for i in range(num//2+1):
# if i * i == num:
# return True
# elif i * i > num:
# return False
#return False
left = 1
right = num//2 + 1
while (left <= right):
mid = (left + right) // 2
if mid * mid == num:
return True
if mid * mid < num:
left = mid + 1
else:
right = mid - 1
return False