程序员面试金典--疯狂刷
位运算经验
粗心点: 乘以2 == <<1
res &= res - 1得到1的位数要远远比直接右移计算最后一位来的好多了!!如果包含符号位则:加一个判断范围:
while res != 0 and res >= -2147483648 and res <= 2147483647 — 其实位数是一样的,0-2147483647 = -1 - -2147483648 共2147483648位。 也就是-2的32次方 ~ 2的32次方-1
感觉题目都不是什么难题,主要还是思路得看过~~毕竟面试题
下面是O(n)的解释:这种递归的计算的时间复杂度是:
具体的解释:
这里的深度是logn,所以也就是得到了O(N)。
注意先序遍历、中序遍历、后续遍历的时间复杂就是O(N)—每个节点都访问了一遍, 空间是O(logn)。不要与快排的O(NLOGN)混淆,快排还夹杂了partition。
BFS优缺点
优点
1、对于解决最短或最少问题特别有效,而且寻找深度小
2、每个结点只访问一遍,结点总是以最短路径被访问,所以第二次路径确定不会比第一次短
缺点
1、内存耗费量大(需要开大量的数组单元用来存储状态)
使用队列。
DFS优缺点: –时间复杂度O(N), 空间复杂度O(d)-比如二叉树的话就是O(logn) 也就是树的深度。
所以前序遍历等等这些的时间复杂度就是O(N)。每一个节点都遍历了!!!!!!!!!!!!!!!!
优点:
能找出所有解决方案
优先搜索一棵子树,然后是另一棵,所以和广搜对比,有着内存需要相对较少的优点
缺点:
要多次遍历,搜索所有可能路径,标识做了之后还要取消。
在深度很大的情况下效率不高
非递归使用栈:
整数转换–必备技能–位运算
class Solution:### 坑栽负数### 不要从低位下手,要从高位下手def convertInteger(self, A: int, B: int) -> int:res = A ^ Bnum = 0while res != 0 and res >= -2147483648 and res <= 2147483647:res &= res-1 # 首位肯定要减去1,后面的位最多加1,num += 1return num#### res &= res - 1得到1的位数要远远比直接右移计算最后一位来的好多了~~#### 如果是右移的话,-1移动一直得到-1,所以溢出。
一 判定字符是否唯一
**位运算 其实很简单,就是26个位置做了个标记,原因是原本只有26个字母。**
这题掌握一个位运算,实现O(N)解决。
class Solution:def isUnique(self, s: str) -> bool:s= sorted(s)for i in range(1, len(s)):if s[i] == s[i-1]:return Falsereturn Trueclass Solution:def isUnique(self, s: str) -> bool:# 位运算mark = 0for i in range(len(s)):tmp = 1res = ord(s[i]) - ord("a")if mark & (tmp << res) != 0:return Falseelse:mark |= (tmp << res)return True
URL化
# 字符串其实不支持修改,尽管给了空间。所以还是要拆开 。 这个一个巨坑就是给足了空间。
# 其次: 如果a = " " 那么a.slpit(" ")其实是得到了多余空格数的""
# a = " "
# print(len(a)) # 5
# a = a.split(" ")
# print(len(a)) # 6
# 所以对于空格的字符后才能 使用split其实不太合适。
# a = "11" a.split("1") == > a = ["", "", ""]
class Solution:def replaceSpaces(self, S: str, length: int) -> str:res = []for c in S[:length]:if c == " ":c = '%20'res.append(c)return ''.join(res)class Solution:def replaceSpaces(self, S: str, length: int) -> str:return S[:length].replace(" ", "%20")
移除重复的节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = Noneclass Solution:def removeDuplicateNodes(self, head: ListNode) -> ListNode:record = {}first = ListNode(None)first.next = headpre= firstres = headwhile res:if res.val in record:pre.next = res.nextres = res.nextelse:record[res.val] = 1res = res.nextpre = pre.nextreturn first.next
链表相交–链表拼接
## 两个链表拼接~~~ 这个思路需要记住的。
class Solution:def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:head1 = headAhead2 = headBdone1 = 0done2 = 0while head1 and head2:if head1 == head2:return head1else:head1 = head1.nexthead2 = head2.nextif not done1 and not head1:head1 = headBdone1 = 1if not done2 and not head2:head2 = headAdone2 = 1return None
环路检测
class Solution:def detectCycle(self, head: ListNode) -> ListNode:if not head or not head.next:return Noneres1 = head.next.nextres2 = head.nextwhile res1 and res2 and res1 != res2:if res1.next:res1 = res1.next.nextelse:return Noneres2 = res2.nextif not res1 or not res2:return Nonenum = 1res2 = res2.nextwhile res2 != res1:res2 = res2.nextnum += 1first = ListNode(0)first.next = headtmp1 = firsttmp2 = firstfor i in range(num):tmp1 = tmp1.nextwhile tmp1 != tmp2:tmp1 = tmp1.nexttmp2 = tmp2.nextreturn tmp1
节点通路–medium
## 广度优先和深度优先
# 下面的思路用了深度优先遍历,然后通过字典来记录。
class Solution:def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int, target: int) -> bool:record = {}for i in range(len(graph)):if graph[i][0] not in record:record[graph[i][0]] = [graph[i][1]]else:record[graph[i][0]] += [graph[i][1]] sign = {}improve = {}def dfs(start, target):if start in sign:return Falseif start not in record:return Falsesign[start] = 1for node in record[start]:if node in sign:return Falseelse:if node == target:return Trueelif node in improve: # 避免重复访问某个节点,一旦存在就说明该节点无法到达target.continueelse:if dfs(node, target):return Trueimprove[start] = Falsesign.pop(start) # sign是避免出现死循环 1 2 3 1, 相当于记录一条路径。 return Falsereturn dfs(start, target)
class Solution:def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int, target: int) -> bool:record = {}for i in range(len(graph)):if graph[i][0] not in record:record[graph[i][0]] = [graph[i][1]]else:record[graph[i][0]] += [graph[i][1]] sign = {}improve = {}def BFS(start, target):if start in sign:return Falseif start not in record:return Falsesign[start] = 1 # 这里没必要用队列。。res = [start]while res:tmp = res.pop()if tmp == target:return Trueif tmp in record:res += record[tmp]return Falsereturn BFS(start, target)
三合一 栈
关键误区:
a = [[]]*3
a[0].append(3)
a[1].append(2)
a[2].append(4)
print(a) # [[3, 2, 4], [3, 2, 4], [3, 2, 4]] ---- 注意会被拷贝。
class TripleInOne:def __init__(self, stackSize: int):self.stackSize = stackSizeself.stack = []# 错误: self.stack = [[]]* 3for i in range(3):self.stack.append([])def push(self, stackNum: int, value: int) -> None:if len(self.stack[stackNum]) < self.stackSize:self.stack[stackNum].append(value)def pop(self, stackNum: int) -> int:if len(self.stack[stackNum]) == 0:return -1return self.stack[stackNum].pop()def peek(self, stackNum: int) -> int:if len(self.stack[stackNum]) == 0:return -1return self.stack[stackNum][-1]def isEmpty(self, stackNum: int) -> bool:if len(self.stack[stackNum]) == 0:return Trueelse:return False
最小高度树
class Solution:def sortedArrayToBST(self, nums: List[int]) -> TreeNode:if not nums:return Noneres = len(nums)//2head = TreeNode(nums[res])head.left = self.sortedArrayToBST(nums[:res])head.right = self.sortedArrayToBST(nums[res+1:])return head
特定深度节点链表
我也有秒杀中等题的能力~~ 注意链表的必胜秘诀就是自己指定一个first,可以避免很多麻烦!!!
from collections import deque
class Solution:def listOfDepth(self, tree: TreeNode) -> List[ListNode]:if not tree:return []queue = deque()queue.append(tree)res = deque()result = []first = ListNode(None)pre = firstwhile queue:node = queue.popleft()pre.next = ListNode(node.val)pre = pre.nextif node.left:res.append(node.left)if node.right:res.append(node.right)if not queue:queue = resres = deque()result.append(first.next)pre = firstreturn result
检查平衡性
通过递归增加深度,然后判断每一棵树的深度,如果深之差大于1,则直接返回false,这样的好处是可以剪枝。
class Solution:def isBalanced(self, root: TreeNode) -> bool:def isbalanced(root):res1 = 0res2 = 0if root.left:res1 = isbalanced(root.left)if not res1:return Falseif root.right:res2 = isbalanced(root.right)if not res2:return Falseif abs(res1 - res2) > 1: # abs这里粗心了return Falseelse:return max(res1, res2) + 1if not root:return Trueif not isbalanced(root):return Falseelse:return True
合法二叉搜索树
二叉搜索树不能出现相等的情况,必须是小于。
class Solution:def isValidBST(self, root: TreeNode) -> bool:self.pre = float("-inf") # 加上负号就是负无穷def mid_search(root):if not root:return Trueres1 = mid_search(root.left)if not res1:return False# 出现相等的情况是错误的。# 左边的每个节点必须小于当前节点,该节点还必须小于右边的所有节点。if root.val <= self.pre:return Falseself.pre = root.valres2 = mid_search(root.right)if not res2:return Falsereturn Truereturn mid_search(root)
后继者
class Solution:def inorderSuccessor(self, root: TreeNode, p: TreeNode) -> TreeNode:self.pre = TreeNode(None) # 注意是真实的下一个点,可能是left也可以能是rightdef mid_search(root, p):if not root:return Noneres = mid_search(root.left, p)if res:return resif self.pre.val == p.val:return rootself.pre = root res = mid_search(root.right, p)if res:return resreturn mid_search(root, p)
公共祖先节点
这道题两个做法,一个是直接递归返回公共节点;另外一种就是记录两条路,然后求第一个链表公共点。
class Solution:def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:def dfs(root, p, q):if not root:return res1 = dfs(root.left, p, q)res2 = dfs(root.right, p, q)if res1 and res2: # 这道题其实不需要考虑这个位置后面是不是虽然已经得到了想要的根节点,但是还更新,因为后面不可能有两个分支都返回,只可能返回一个。return rootif root == p or root == q:return rootif res1:return res1else:return res2return dfs(root, p, q)
较麻烦的写法:
class Solution:def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:## 这道题的一个坑是不能只是用两个标志来判定是否达到了,因为p或q节点可能就是祖先节点。## 所以应该是 从下往上的返回值更加稳妥。self.p = 0self.q = 0self.result = Nonedef dfs(root, p, q):if not root:return 0 res1 = dfs(root.left, p, q)res2 = dfs(root.right, p, q)if root == p and (res1 | res2):if not self.result:self.result = rootreturn 1if root == q and (res1 | res2):if not self.result:self.result = rootreturn 1if res1 and res2:if not self.result:self.result = rootreturn 1 if root == p or root == q:return 1return res1 | res2dfs(root, p, q)return self.result
插入
class Solution:def insertBits(self, N: int, M: int, i: int, j: int) -> int:res = 0allone = 1while allone <= N:allone = allone << 1allone -= 1# for m in range(j-i+1): # 坑1: j-i+1不是+2# res += 2**m# 比如i=2, j=6,那么其实就是要产生5位1,range5就可以---实在不行就套入实例。res = 1res = res << (j-i+1) # 原本就有一位1了,所以只需要移动5位,一共就6,-1得5res -= 1res = res << iallone -= resM = M << i # 注意M也要左移!!N = N & allonereturn N | M
整数转换–必备技能–位运算
class Solution:### 坑栽负数### 不要从低位下手,要从高位下手def convertInteger(self, A: int, B: int) -> int:res = A ^ Bnum = 0while res != 0 and res >= -2147483648 and res <= 2147483647:res &= res-1 # 首位肯定要减去1,后面的位最多加1,num += 1return num#### res &= res - 1得到1的位数要远远比直接右移计算最后一位来的好多了~~#### 如果是右移的话,-1移动一直得到-1,所以溢出。
配对交换
也是思路题目,但是不难,就是分别提取出奇数位和偶数位,然后奇数位左移,偶数位右移。
class Solution:def exchangeBits(self, num: int) -> int:# 奇数位右移动, 偶数位左移动# if num < 2:# return numres1 = 1while (res1 << 2) + 1 < 2**30:res1 = res1 << 2res1 += 1res2 = 2while (res2 << 2) + 2 < 2**30:res2 = (res2 << 2) + 2# res1 = 0x55555555 # int32位, ox是16进制, ob是二进制# res2 = 0xAAAAAAAAreturn ((num & res1) << 1) + ((num & res2) >> 1)
旋转矩阵
想象一下 3*3, 想象j+1之后的结果,还是可以列出来四个点的位置的。然后就是得带。
其实也就是旋转一圈,难点在于行和列其实不一定是固定的i、j,j也可以在行的位置上。 只能旋转一半,如果是奇数,比如5,旋转一半则应该到3,所以是(N+1)//2; 如果是偶数,也可以是(N+1)//2.
行的话是直接N//2即可,因为如果是奇数,N==5, 第三行其实已经换好了。 很明显就是3*3,只需要用到第一行。
class Solution:def rotate(self, matrix: List[List[int]]) -> None:if not matrix:return matrixN = len(matrix)for i in range(N//2):for j in range((N+1)//2): # 占据一半matrix[i][j], matrix[j][N-i-1], matrix[N-i-1][N-j-1], matrix[N-j-1][i] = matrix[N-j-1][i], matrix[i][j], matrix[j][N-i-1], matrix[N-i-1][N-j-1]return matrixclass Solution:def rotate(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""if not matrix:return matrixN = len(matrix)for i in range(N//2):for j in range((N-1)//2+1): # 占据一半matrix[i][j], matrix[j][N-i-1] = matrix[j][N-i-1], matrix[i][j]matrix[i][j], matrix[N-i-1][N-j-1] = matrix[N-i-1][N-j-1], matrix[i][j]matrix[i][j], matrix[N-j-1][i] = matrix[N-j-1][i], matrix[i][j]return matrix
错误的集合
属于一道面试不难,但是错误百出的题。题意要看清,注意是从1-n, n是数组的数目,所以说明每一个数都是不可或缺的。所以不排序用空间的话 就 查找重复的和缺失的。
2、思路二 是空间只用logn,也就是先排序。 判断两个数之间相差大于1,肯定缺失,额外的情况是确实1/n,所以要额外考虑。
class Solution:def findErrorNums(self, nums: List[int]) -> List[int]:if len(nums) < 2:return []### 措大了!!!! 不一定是相邻的~~ ### 首先1-n很重要,说明一定在这个区间,n还是数目,说明每一个数都是不可或缺的。### 所以只需要找到缺少的数,以及多余的数,就可以了。根本不需要排序n = len(nums)res = {}res[nums[0]] = 1for i in range(1, len(nums)):if nums[i] in res:res1 = nums[i]res[nums[i]] = 1for i in range(1, n+1):if i not in res:return [res1, i]class Solution:def findErrorNums(self, nums):if len(nums) < 2:return []nums = sorted(nums)n = len(nums)res1, res2 = 0, 0if nums[0] != 1: ### 排序,首位要额外考虑。res2 = 1for i in range(1, len(nums)):if nums[i] - nums[i - 1] > 1:res2 = nums[i] - 1if nums[i] == nums[i - 1]:res1 = nums[i]if not res2:res2 = nreturn [res1, res2]
递归算法
其实不使用移位的算法更加牛逼~~每次就是减少一个A/B, 挑少的减去。不过缺点就是栈可能溢出。
class Solution:def multiply(self, A: int, B: int) -> int:if B == 1:return Aif B == 2:return (A << 1)if B % 2 != 0:return self.multiply(A, B-1) + Aif B > 2:return self.multiply(A, B//2) << 1class Solution:def multiply(self, A: int, B: int) -> int:if B == 0 or A == 0:return 0if A < B:return self.multiply(A-1, B) + Belse:return self.multiply(A, B-1) + A
回溯-括号
注意点在左括号已经到了n,这时候不可以使用左括号。
class Solution:def generateParenthesis(self, n: int) -> List[str]:result = []def backtrack(n, left, right, res):if left == n and right == n:result.append(res)return for i in ["(", ")"]:if left > right:if i == "(":if left < n: # 这里要注意~~~backtrack(n, left+1, right, res+i)else:backtrack(n, left, right+1, res+i)elif left == right:if i == "(":backtrack(n, left+1, right, res+i)else:passbacktrack(n, 0, 0, "")return result
颜色填充
class Solution:def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:res = image[sr][sc]##### 这一步,太尼玛关键了!并且记住无论合适,递归都给我返回一致的东西。if image[sr][sc] == newColor:return imageimage[sr][sc] = newColorif sr + 1 < len(image) and image[sr+1][sc] == res:self.floodFill(image, sr+1, sc, newColor)if sr - 1 >= 0 and image[sr-1][sc] == res:self.floodFill(image, sr-1, sc, newColor)if sc - 1 >= 0 and image[sr][sc-1] == res:self.floodFill(image, sr, sc-1, newColor)if sc + 1 < len(image[0]) and image[sr][sc+1] == res:self.floodFill(image, sr, sc+1, newColor)return image
堆箱子
不要复杂化,就是往上堆,不用想着平堆~~ 本意没有这个意思
**其实就是相当于每一个箱子都有可能是起点。dp[i]代表的是使用当前箱子能得到的最大的高度。**使用当前箱子的时候去判断之前的箱子有没有可以套他的,可以的话 就增长了~~
class Solution:def pileBox(self, box: List[List[int]]) -> int:boxes = sorted(box, key=lambda x:-x[0])# 动态规划dp = []n = len(boxes)dp = [0]*ndp[0] = boxes[0][2]for i in range(1, n):tmp = boxes[i][2]for j in range(i):if boxes[j][1] > boxes[i][1] and boxes[j][2] > boxes[i][2] and boxes[j][0] > boxes[i][0]: # 就算是排序了第一个,还是要判断,可能相等。tmp = max(tmp, dp[j]+boxes[i][2])dp[i] = tmpreturn max(dp)
### 其实就是相当于每一个箱子都有可能是起点。dp[i]代表的是使用当前箱子能得到的最大的高度。
最长递增子序列
class Solution:def lengthOfLIS(self, nums: List[int]) -> int:n = len(nums)dp = [0]*nfor i in range(n):dp[i] = 1for j in range(i):if nums[i] > nums[j]:dp[i] = max(dp[i], dp[j]+1)return max(dp)
二进制数转字符串
class Solution:def printBin(self, num: float) -> str:## 0.625 => 0.101 也就是2的负1次方乘以1,加上2的负-3次方乘以1tmp = 0.5res = 2result = "0."while res < 32: # 判断条件下才执行if num == 0:breakif tmp > num:tmp = tmp / 2result += "0"else:num = num - tmptmp /= 2result += "1"res += 1if num == 0:return resultelse:return "ERROR"
动物收容所
这道题有个点是其实不需要第三个 队列来返回任意的,其实可以比较编号,编号越小,说明越早进。
from collections import dequeclass AnimalShelf:def __init__(self):self.dog = deque()self.cat = deque()# self.queue = deque()def enqueue(self, animal: List[int]) -> None:if animal[1] == 0:self.cat.append(animal[0])else:self.dog.append(animal[0])# self.queue.append(animal[0])def dequeueAny(self) -> List[int]:if not self.cat and not self.dog:return [-1, -1]elif not self.cat:return [self.dog.popleft(), 1]elif not self.dog:return [self.cat.popleft(), 0]else:if self.dog[0] < self.cat[0]:return [self.dog.popleft(), 1]else:return [self.cat.popleft(), 0]# if self.queue:# res = self.queue.popleft()# if self.cat and res == self.cat[0]:# self.cat.popleft()# return [res, 0]# else:# self.dog.popleft()# return [res, 1]# else:# return [-1, -1]def dequeueDog(self) -> List[int]:if self.dog:res = self.dog.popleft()# self.queue.remove(res)return [res, 1]else:return [-1, -1]def dequeueCat(self) -> List[int]:if self.cat:res = self.cat.popleft()# self.queue.remove(res)return [res, 0]else:return [-1, -1]
# Your AnimalShelf object will be instantiated and called as such:
# obj = AnimalShelf()
# obj.enqueue(animal)
# param_2 = obj.dequeueAny()
# param_3 = obj.dequeueDog()
# param_4 = obj.dequeueCat()
堆盘子
坑在cap <= 0
class StackOfPlates:def __init__(self, cap: int):self.stack = []self.cap = capdef push(self, val: int) -> None:if self.cap <= 0: # 无语的坑爹return if not self.stack:self.stack.append([val])elif len(self.stack[-1]) == self.cap:self.stack.append([val])else:self.stack[-1].append(val)def pop(self) -> int:if not self.stack:return -1res = self.stack[-1].pop()if not self.stack[-1]:self.stack.pop()return resdef popAt(self, index: int) -> int:if index >= len(self.stack):return -1res = self.stack[index].pop()if not self.stack[index]:self.stack.pop(index)return res
幂集
class Solution:def subsets(self, nums: List[int]) -> List[List[int]]:result = []def backtrack(routes, sign):result.append(list(routes))if sign == len(nums):return for i in range(sign, len(nums)):backtrack(routes + [nums[i]], i+1) # 不是sign+1backtrack([], 0)return result
检查子树
class Solution:def waysToChange(self, n: int) -> int:nums = [1, 5, 10, 25]dp = []dp = [0]*(n+1)dp[0] = 1res = list(dp)for i in range(1, len(nums)+1):for j in range(1, n+1):if j - nums[i-1] >= 0:dp[j] = dp[j-nums[i-1]] +res[j]dp[j] %= 1000000007res = list(dp)return dp[-1]
class Solution:def checkSubTree(self, t1: TreeNode, t2: TreeNode) -> bool:### 这道题必须是完全一模一样的子树,不可以是只有一部分if not t2:return Truedef dfs(t1, t2):if not t1 and t2:return Falseelif not t1 and not t2:return Trueres1 = dfs1(t1, t2)if res1:return Trueres2 = dfs(t1.left, t2)if res2:return Trueres3 = dfs(t1.right, t2)if res3:return Truereturn Falsedef dfs1(t1, t2):if not t1 and not t2:return Trueelif not t1:return Falseelif not t2:return Falseres1 = 0res2 = 0if t1.val == t2.val:res1 = dfs1(t1.left, t2.left)if res1:res2 = dfs1(t1.right, t2.right) if res1 and res2:return Truereturn Falseelse:return Falsereturn dfs(t1, t2)
组合–完全背包问题
dp[i][j]代表的是使用i枚硬币达到金额j的组合数
组合的规律是 dp[i][j] = dp[i][j-nums[j]] + dp[i-1][j]
优化的话就是使用两个列表来解决了,一个是无法解决的。
class Solution:def waysToChange(self, n: int) -> int:nums = [1, 5, 10, 25]dp = []dp = [0]*(n+1)dp[0] = 1res = list(dp)for i in range(1, len(nums)+1):for j in range(1, n+1):if j - nums[i-1] >= 0:dp[j] = dp[j-nums[i-1]] +res[j]dp[j] %= 1000000007res = list(dp)return dp[-1]
# 完全背包--组合问题
class Solution:def waysToChange(self, n: int) -> int:nums = [1, 5, 10, 25]dp = []# dp[i][j]代表的是使用i枚硬币达到金额j的组合数# 组合的规律是 dp[i][j] = dp[i][j-nums[j]] + dp[i-1][j]for i in range(len(nums)):dp.append([0]*(n+1))for i in range(len(nums)):dp[i][0] = 1for i in range(1, len(nums)):for j in range(1, n+1):if j - nums[i-1] >= 0:dp[i][j] = dp[i][j-nums[i-1]] + dp[i-1][j]dp[i][j] %= 1000000007else:dp[i][j] = dp[i-1][j]dp[i][j] %= 1000000007return dp[-1][-1]
链表求和
## 最好还是不要改变原有的链表,自己创建一个比较合适。
class Solution:def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:head1 = l1head2 = l2add = 0first = ListNode(None)pre = firstwhile head1 and head2:res = (head1.val + head2.val + add) % 10add = (head1.val + head2.val + add) // 10pre.next = ListNode(res)pre = pre.nexthead2 = head2.nexthead1 = head1.nextif not head1 and not head2:if add:pre.next = ListNode(add)return first.nextelif not head1:while head2:res = (head2.val + add) % 10add = (head2.val + add) // 10pre.next = ListNode(res)head2 = head2.nextpre = pre.nextif add:pre.next = ListNode(add)return first.nextelse:while head1:res = (head1.val + add) % 10add = (head1.val + add) // 10pre.next = ListNode(res)head1 = head1.nextpre = pre.next ### 遗漏点if add:pre.next = ListNode(add)return first.next
魔术索引
class Solution:def findMagicIndex(self, nums: List[int]) -> int:i = 0while i < len(nums):if nums[i] == i:return ires = nums[i]if res > len(nums):return -1if res > i:i = res - 1i += 1return -1
如果是严格单调递增:
### 严格单调递增
class Solution:def findMagicIndex(self, nums):left = 0right = len(nums) - 1result = len(nums)while left <= right:mid = (left + right)//2if nums[mid] > mid:right = mid - 1elif nums[mid] < mid:left = mid + 1else:result = min(result, mid)right = mid - 1if result == len(nums):return -1else:return result
无重复字符串的排列组合
class Solution:def permutation(self, S: str) -> List[str]:result = []record = {}def backtrack(S, sub):if len(sub) == len(S):result.append(sub)return for i in range(len(S)):if i not in record:record[i] = 1backtrack(S, sub+S[i])record.pop(i)backtrack(S, "")return resultclass Solution:def permutation(self, S: str) -> List[str]:result = []record = {}def backtrack(S, sub):if not S:result.append(sub)returnfor i in range(len(S)): backtrack(S[0:i]+S[i+1:], sub+S[i])backtrack(S, "")return result
稀疏数组搜索
class Solution:def findString(self, words: List[str], s: str) -> int:if not words:return -1left = 0right = len(words)-1while left <= right:mid = (left + right) // 2res = mid while res >= 0 and words[res] == "":res -= 1if res == -1:left = mid + 1continueif words[res] > s:right = res - 1elif words[res] < s:left = mid + 1else:return resreturn -1
交换数字
位运算 与0 异或保持不变, 与1异或就是取反。
class Solution:def swapNumbers(self, numbers: List[int]) -> List[int]:numbers[0] = numbers[0] ^ numbers[1]numbers[1] = numbers[0] ^ numbers[1]numbers[0] = numbers[0] ^ numbers[1]return numbers
最小差
class Solution:def smallestDifference(self, a: List[int], b: List[int]) -> int:res1 = 0res2 = 0pre = 0min_dif = float("inf")a = sorted(a)b = sorted(b)while res1 < len(a) and res2 < len(b):if a[res1] < b[res2]:min_dif = min(abs(a[res1]-b[res2]), min_dif)res1 += 1else:min_dif = min(abs(a[res1]-b[res2]), min_dif)res2 += 1return min_dif
有重复字符串的排列组合
有重复的字符串的组合:
class Solution:def permutation(self, S: str) -> List[str]:record = {}S = sorted(S)result = []for i in range(len(S)):record[i] = 0############################### 一个失误点:record最好也是直接记录序号,不然很麻烦。sign = {}def backtrack(S, sub):if len(sub) == len(S):result.append(sub)return for i in range(len(S)):if i in sign:continueif i >= 1 and S[i] == S[i-1] and record[i-1]==0:continuerecord[i] = 1sign[i] = 1backtrack(S, sub+S[i])sign.pop(i)record[i] = 0backtrack(S, "")return result
无重复元素+无限制重复–此时就是直接用了一个标记,下一次不能小于上一次的标记,也就是不会返回。只会重复当前数或者是往后走~~ 39组合总和
如果只是无重复元素,每一个只能使用一次的话,那么直接用字典记录就可以了。
有重复元素, 只能使用一次-- 先排序,多使用一个字典来标记,记住全部标记序号,如果nums[i] == nums[i-1] and i-1 not in record,则continue;
有重复元素,无限次使用,其实没有意义,重复包含在无限次里了。
最大数值
两个数的差值的绝对值~
其实上述做法有个问题,如果不使用abs,如果从一个负数/正数 得到他的绝对值。
跳水板
递归超时,还是需要数学规律。其实这一题很有规律。很容易发现。做题还是多罗列几个~~~
class Solution:def divingBoard(self, shorter: int, longer: int, k: int) -> List[int]:# 递归超时if k == 0:return []result = set()def backtrack(shorter, longer, k, sign, sum, num):if num == k:result.add(sum)return for i in range(shorter, longer+1):if i < sign:continuebacktrack(shorter, longer, k, i, sum+i, num+1)backtrack(shorter, longer, k, 0, 0, 0)return list(result)### 规律题 还是要多罗列几个,发现规律,不要盲目下手~~很重要。
class Solution:def divingBoard(self, shorter: int, longer: int, k: int) -> List[int]:if not k:return []if longer == shorter:return [longer*k]res = (longer-shorter)*k+1 # 总数result = []num = 0for i in range(k*shorter, k*shorter+res, longer-shorter):result.append(i)return result
贪心-连续数列
class Solution:def maxSubArray(self, nums: List[int]) -> int:## 贪心而已if not nums:return 0res = 0result = float("-inf")for i in range(len(nums)):if res < 0:res = nums[i] elif nums[i] + res < 0:res = nums[i] # 这个是必须的,不然会跳位else:res = nums[i] + resresult = max(result, res)return result
动态规划
这道题的转移条件还是蛮难的。如果加上一位之后,不能与之前的所有形成建,那么就是上一个的dp值加1,如果可以形成键,那么就是取该值与当前值对比。
class Solution:def respace(self, dictionary: List[str], sentence: str) -> int:## 未识别的字符数--是字符 不是单词数## 这题加上一位有点难弄。n = len(sentence)dp = [1000000]*(n+1)dp[0] = 0for i in range(1, n+1):dp[i] = dp[i-1] + 1for j in range(0, i):if sentence[j:i] in dictionary:dp[i] = min(dp[i], dp[j]) # 这里不是j-1的原因是dp是n+1的长度return dp[-1]# ## 错误
# class Solution:
# def respace(self, dictionary: List[str], sentence: str) -> int:# ## 以下解法无法解决的情况: 因为确实存在没有字符的,没有字符应该是0.如果没有考虑的话,那么计算
# # 会出问题
# # ["potimzz"] "potimzzpotimzz" ## 并且有很多情况,所以如果是动态规划,并且是记录从某一位到某一位的,注意还是加上一位!!!!
# ## 未识别的字符数--是字符 不是单词数
# ## 这题加上一位有点难弄。
# n = len(sentence)
# dp = [1000000]*n
# if sentence[0] in dictionary:
# dp[0] = 0
# else:
# dp[0] = 1
# for i in range(1, n):
# dp[i] = dp[i-1] + 1
# for j in range(0, i):
# if sentence[j:i+1] in dictionary:
# if j == 0:
# dp[i] = 0
# else:
# dp[i] = min(dp[i], dp[j-1])
# return dp[-1]
程序员面试金典--疯狂刷相关推荐
- 程序员面试金典面试题 01.06. 字符串压缩
前言 本系列文章为<程序员面试金典>刷题笔记. 题目位置:字符串压缩 题集:程序员面试金典 题目 字符串压缩.利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能.比如,字符串a ...
- C#LeetCode刷题-程序员面试金典
本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:C#LeetCode刷题-程序员面试金典 | .Net中文网. C#LEETCODE刷题概述 概述 所有LeetCode程序员面试金典 ...
- 程序员面试金典1.1
程序员面试金典1.1 重新用java刷一遍,熟悉java语言 文章目录 程序员面试金典1.1 1. 二次遍历 2.哈希表Map 3.利用set的不可重复性 4.用数组 5.位运算 6.用String自 ...
- 程序员面试金典--第k个数
程序员面试金典--第k个数 题目描述 有一些数的素因子只有3.5.7,请设计一个算法,找出其中的第k个数. 给定一个数int k,请返回第k个数.保证k小于等于100. 测试样例: 3 返回:7 逐个 ...
- 程序员面试金典 - 面试题 08.13. 堆箱子(DP)
1. 题目 堆箱子.给你一堆n个箱子,箱子宽 wi.深 di.高 hi. 箱子不能翻转,将箱子堆起来时,下面箱子的宽度.高度和深度必须大于上面的箱子. 实现一种方法,搭出最高的一堆箱子.箱堆的高度为每 ...
- 程序员面试金典 - 面试题 17.08. 马戏团人塔(最长上升子序 DP/二分查找)
文章目录 1. 题目 2. 解题 2.1 超时解 2.2 二分查找 1. 题目 有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上.出于实际和美观的考虑,在上面的人要比下面的人矮一点且轻一 ...
- 《程序员面试金典》解题目录(更新完毕)
题目来源于LeetCode上的<程序员面试金典>,这里做一个目录方便大家查找.另外有本人的LeetCode解题目录.<剑指Offer>解题目录.LintCode代码能力测试CA ...
- 《程序员面试金典》+《算法导论》
<程序员面试金典>+<算法导论> 因为最近可能会面临一波面试,但是自己各种算法以及常见的问题的熟悉程度感觉还不够,但是由前几次的代码优化经验来看,算法优化可以说是代码优化的重中 ...
- 程序员面试金典——18.13 最大字母矩阵
程序员面试金典--18.13 最大字母矩阵 在牛客网上把此题的难度给大大降低了......... Solution1: 参考网址:https://www.nowcoder.com/questionTe ...
- 程序员面试金典——18.12最大和子矩阵
程序员面试金典--18.12最大和子矩阵 Solution1: 参考网址: [1]https://www.cnblogs.com/GodA/p/5237061.html 思想讲的很清楚~ [2]htt ...
最新文章
- 教你设计一个超牛逼的本地缓存!
- mysql commit慢_mysql autocommit问题导致的gtid同步变慢
- 「讨论」测试工程师能否作为一份终生职业?30岁+怎么办?
- UVA725 UVALive5362 Division【暴力+进制】
- Guitar Pro8(简称GTP8)正式版吉他谱神器
- imageJ使用手册
- 如何对多个文件夹进行重命名?这个方法可以批量修改文件夹名、给文件夹名加统一前缀或后缀
- 计算机操作系统之CPU架构和原理(二)
- STM32 AD采样基准电压
- adsl双网卡共享上网的设置(win2003)
- python三维图形注释_python – Matplotlib:注释3D散点图
- a href=javascript作用
- 百谷歌---学习工作好东西啊!!
- 最近流行剪刀手 ^_^
- 后端存储课程笔记(大量实战经验)
- 0521MySQL常用操作---设置更改root密码、数据库备份恢复、连接mysql、mysql用户管理...
- delphi的bpl、dcp 、dcu文件意义
- Endnote连接Word自动插入毕业论文参考文献
- 【建议】个人竞争力≠个人竞争力模型
- 联想ThinkPad系列笔记本进bios设置u盘启动教程
热门文章
- 你真的了解LinkedBlockingQueue的put,add和offer的区别吗
- [论文笔记]Outfit Compatibility Prediction and Diagnosis with Multi-Layered Comparison Network
- 常微分方程机敏问答[1] #20210611
- 喜讯!云效度量能力获信通院先进级评估
- 网络远程计算机终止,电脑拨号上网出现错误629:连接被远程计算机终止怎么办...
- 我的团长我的团第八集
- li序号 ul_ul ol li的序号编号样式
- win7上搭建ftp站点
- 首发|罗振宇2018“时间的朋友”跨年演讲未删减全文
- 问道服务器etc修改教程,常用的修改etc对照表-详细版