题1 两数之和
解:哈希思想,时间复杂度O(n),空间复杂度O(n)
Class Solution:
def twoSum(self, nums, target):
dict = {}
for i,item in enumerate(nums):
if item not in dict: dict[target-item]=i
else: return[dict[item], i]
题3 无重复字符的最长子串
解:维护一个滑动窗口,并构建一个辅助集合收集当前窗口的全部字符,来判断是否有重复字符。
时间复杂度O(n),空间复杂度O(n)
class Solution:
def LengthOfLongestSubstring(self, s):
if not s: return 0
# 记录当前窗口左端位置
left = 0
# 记录当前窗口长度
cur_len = 0
# 记录符合条件的最长窗口长度
max_len = 0
# 构建辅助集合
lookup = set()
for i in range(len(s)):
cur_len += 1
while s[i] in lookup:
# 窗口左边界右滑,窗口长度缩小,更新辅助集合
lookup.remove(s[left])
left += 1
cur_len -= 1
lookup.add(s[i])
if max_len < cur_len: max_len = cur_len
return max_len
题2 两数相加
解一:递归
class Solution:
def addTwoNumbers(self, l1, l2):
if not l1:
return l2
if not l2:
return l1
l1.val += l2.val
if l1.val >= 10:
l1.next = self.addTwoNumbers(ListNode(l1.val//10), l1.next)
l1.val %= 10
l1.next = self.addTwoNumbers(l1.next, l2.next)
return l1
解二:迭代
class Solution:
def addTwoNumbers(self, l1, l2):
# 构建一个空头指针的新链表,来存储结果
head = p = ListNode()
# 表示当前数位结果,和下一数位的值
cur = nex = 0
# 终止条件
while l1 or l2 or nex:
cur = nex
if l1:
cur += l1.val
l1 = l1.next
if l2:
cur += l2.val
l2 = l2.next
nex = cur // 10
cur = cur % 10
# 插入新结点
p.next = ListNode(cur)
p = p.next
return head.next
剑指题9 用两个栈实现队列
解:
class CQueue:
def __init__(self):
self.in_stack = []
self.out_stack = []
def appendTail(self, value):
self.in_stack.append(value)
def deleteHead(self):
if self.out_stack: return self.out_stack.pop()
if not self.in_stack: return -1
while self.in_stack: self.out_stack.append(self.in_stack.pop())
return self.out_stack.pop()
题1480 一维数组的动态和
解:
class Solution:
def runningSum(self, nums):
for i in range(1, len(nums)):
nums[i] += nums[i-1]
return nums
题5 最长回文子串
解一:Manacher. 有以下几个关键点:一是插特殊字符来统一奇偶两种情况;二是维护一个记录臂展的辅助数组;三是记录已知的回文子串到达的最远位置,目的是充分利用探索过的信息,避免重复探索;四是利用回文串的对称性
class Solution:
# 两侧延伸求臂展
def expand(self, s, left, right):
while left >= 0 and right <= len(s)-1 and s[left] == s[right]:
left -= 1
right += 1
return (right-left-2) // 2
def longestPalindrome(self, s):
# 方便统一处理
s = '#' + '#'.join(list(s)) + '#'
# 记录臂展数组
arms = []
# 记录最大回文子串
start, end = -1, -1
# 记录已探索的最右边界和对应的对称中心
center, right = -1, -1
# 遍历更新
for i in range(len(s)):
if right > i:
# 找到i关于center的对称点
i_mirror = 2 * center - i
# Manacher方法的精华都在这一行里,利用了对称点的已知信息
cur_arm = min(right-i, arms[i_mirror])
cur_arm = self.expand(s, i-cur_arm, i+cur_arm)
else:
cur_arm = self.expand(s, i, i)
# 求得当前位置i臂展后,更新需要记录的变量
arms.append(cur_arm)
if i + cur_arm > right:
center, right = i, i + cur_arm
if 2 * cur_arm >= end - start:
start, end = i - cur_arm, i + cur_arm
return s[start+1:end:2]
解二:中心扩展
class Solution:
def expand(self, s, left, right):
while left >= 0 and right <= len(s)-1 and s[left] == s[right]:
left -= 1
right += 1
return left+1, right-1
def longestPalindrome(self, s):
left, right = -1, -1
for i in range(len(s)):
left1, right1 = self.expand(s, i, i)
left2, right2 = self.expand(s, i, i+1)
if right2 - left2 >= right - left:
left, right = left2, right2
if right1 - left1 >= right - left:
left, right = left1, right1
return s[left:right+1]
解三:动态规划,鸡肋解法
class Solution:
def longestPalindrome(self, s):
if len(s) < 2: return s
start, end = 0, 0
n = len(s)
dp = [[False] * n for _ in range(n)]
for i in range(n):
dp[i][i] = True
for L in range(1, n+1):
for i in range(n):
j = i + L - 1
if j >= n: break
if s[i] != s[j]: dp[i][j] = False
else:
if j - i < 2: dp[i][j] = True
else: dp[i][j] = dp[i+1][j-1]
if dp[i][j] and j - i > end - start:
start, end = i, j
return s[start:end+1]