classSolution: defGetNext(self, pNode): if pNode.right: cur = pNode.right while cur.left: cur = cur.left return cur else: cur = pNode while cur.nextand cur.next.right == cur: cur = cur.next return cur.next
classSolution: defFibonacci(self , n: int) -> int: if n <= 2: return1 a, b = 1, 1 for _ inrange(n-2): a, b = b, a+b return b
JZ11 旋转数组的最小数字
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
1 2 3 4 5 6 7 8 9
classSolution: defminNumberInRotateArray(self , nums: List[int]) -> int: l, r = 0, len(nums)-1 while l < r: m = (l+r) // 2 if nums[m] > nums[r]: l = m + 1 elif nums[m] < nums[r]: r = m else: r -= 1 return nums[r]
classSolution: defhasPath(self , matrix: List[List[str]], word: str) -> bool: ifnot matrix: returnFalse m, n, flag = len(matrix), len(matrix[0]), False defdfs(i, j, k): nonlocal flag if flag: return if k == len(word): flag = True return visit[i][j] = True#标记为已经过 if i>0andnot visit[i-1][j] and matrix[i-1][j] == word[k]: dfs(i-1, j, k+1) if i<m-1andnot visit[i+1][j] and matrix[i+1][j] == word[k]: dfs(i+1, j, k+1) if j>0andnot visit[i][j-1] and matrix[i][j-1] == word[k]: dfs(i, j-1, k+1) if j<n-1andnot visit[i][j+1] and matrix[i][j+1] == word[k]: dfs(i, j+1, k+1) visit[i][j] = False#无路可走,回退,消除标记 return for i inrange(m): for j inrange(n): visit = [[False] * n for _ inrange(m)] if matrix[i][j] == word[0]: dfs(i,j,1) return flag
classSolution: defdfs(self, matrix: List[List[str]], n: int, m: int, i: int, j: int, word: str, k: int, flag: List[List[bool]]) -> bool: if i < 0or i >= n or j < 0or j >= m or (matrix[i][j] != word[k]) or flag[i][j]: #下标越界、字符不匹配、已经遍历过不能重复 returnFalse #k为记录当前第几个字符 if k == len(word) - 1: returnTrue flag[i][j] = True #该结点任意方向可行就可 if (self.dfs(matrix, n, m, i - 1, j, word, k + 1, flag) orself.dfs(matrix, n, m, i + 1, j, word, k + 1, flag) orself.dfs(matrix, n, m, i, j - 1, word, k + 1, flag) orself.dfs(matrix, n, m, i , j + 1, word, k + 1, flag)): returnTrue #没找到经过此格的,此格未被占用 flag[i][j] = False returnFalse
defhasPath(self , matrix: List[List[str]], word: str) -> bool: iflen(matrix) == 0: returnFalse n = len(matrix) m = len(matrix[0]) #初始化flag矩阵记录是否走过 flag = [[Falsefor i inrange (m)] for j inrange(n)] #遍历矩阵找起点 for i inrange(n): for j inrange(m): #通过dfs找到路径 ifself.dfs(matrix, n, m, i, j, word, 0, flag): returnTrue returnFalse
给你一根长度为 n 的绳子,请把绳子剪成整数长的 m 段( m 、 n 都是整数, n > 1 并且 m > 1 , m <= n ),每段绳子的长度记为 k[1],…,k[m] 。请问 k[1]k[2]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是 8 时,我们把它剪成长度分别为 2、3、3 的三段,此时得到的最大乘积是 18 。
1 2 3 4 5
if n <= 3: return n-1 m, k = n // 3, n % 3 if k == 0: return3**m elif k == 1: return3**(m-1)*4 elif k == 2: return3**m*2
JZ15 二进制中1的个数
输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。
1 2 3 4 5 6 7
classSolution: defNumberOf1(self , n: int) -> int: res = 0 for _ inrange(32): if n & 1: res += 1 n >>= 1 return res
JZ16 数值的整数次方
实现函数 double Power(double base, int exponent),求base的exponent次方。
注意:
1.保证base和exponent不同时为0。
2.不得使用库函数,同时不需要考虑大数问题
3.有特殊判题,不用考虑小数点后面0的位数。
1 2 3 4 5 6 7 8
classSolution: defPower(self , base: float, exponent: int) -> float: res = 1 if exponent < 0: base, exponent = 1/base, -exponent for _ inrange(exponent): res *= base return res
classSolution: defprintNumbers(self , n: int) -> List[int]: res = [i for i inrange(1,10**n)] return res
JZ18 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。
1.此题对比原题有改动
2.题目保证链表中节点的值互不相同
3.该题只会输出返回的链表和结果做对比,所以若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
1 2 3 4 5 6 7
classSolution: defdeleteNode(self , head: ListNode, val: int) -> ListNode: if head.val == val: return head.next#判断头节点 cur = head while cur.next.val != val: cur = cur.next cur.next = cur.next.next return head
#有限状态机 classSolution: defisNumeric(self , str): state = [{' ':0, 's':1, 'd':2, '.':4}, {'d':2, '.':4}, {'d':2, '.':3, 'e':5, ' ':8}, {'d':3, 'e':5, ' ':8}, {'d':3}, {'s':6, 'd':7}, {'d':7}, {'d':7, ' ':8}, {' ':8}] p = 0 for c instr: if'0' <= c <= '9': t = 'd' elif c in'+-': t = 's' elif c in'Ee': t = 'e' elif c in'. ': t = c else: t = '?' if t notin state[p]: returnFalse p = state[p][t] return p in [2,3,7,8]
JZ21 调整数组顺序使奇数位于偶数前面(一)
输入一个长度为 n 整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
1 2 3 4 5 6 7 8
#时间O(N),空间O(N) classSolution: defreOrderArray(self , array: List[int]) -> List[int]: odd, even = [], [] for m in array: if m % 2: odd.append(m) else: even.append(m) return odd + even
1 2 3 4 5 6 7 8 9 10 11
#时间O(N2),空间O(1) classSolution: defreOrderArray(self , array: List[int]) -> List[int]: i = 0 while i < len(array): if array[i] % 2: while i>0and array[i-1] % 2 == 0: array[i-1], array[i] = array[i], array[i-1] i -= 1 i += 1 return array
JZ22 链表中倒数最后k个结点
输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。
如果该链表长度小于k,请返回一个长度为 0 的链表。
1 2 3 4 5 6 7 8 9 10 11
#单指针 classSolution: defFindKthToTail(self , pHead: ListNode, k: int) -> ListNode: node_num = 0 cur = pHead while cur: node_num += 1 cur = cur.next if node_num < k: returnNone for _ inrange(node_num-k): pHead = pHead.next return pHead
1 2 3 4 5 6 7 8 9 10 11
#双指针 classSolution: defFindKthToTail(self , pHead: ListNode, k: int) -> ListNode: cur = pHead for _ inrange(k): ifnot cur: returnNone cur = cur.next while cur: cur = cur.next pHead = pHead.next return pHead
1 2 3 4 5 6 7 8 9 10 11 12
#栈 classSolution: defFindKthToTail(self , pHead: ListNode, k: int) -> ListNode: stk = [] while pHead: stk.append(pHead) pHead = pHead.next iflen(stk) < k: return cur = None for _ inrange(k): cur = stk.pop() return cur
JZ23 链表中环的入口结点
给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defEntryNodeOfLoop(self, pHead): fast = slow = pHead while fast and fast.next: #快慢指针 fast = fast.next.next slow = slow.next if fast == slow: fast = pHead #将快指针移到头结点,一起走a步到入口处 break else: return while fast != slow: fast = fast.next slow = slow.next return fast
classSolution: defReverseList(self , head: ListNode) -> ListNode: pre, tmp = None, head while head: head = head.next tmp.next = pre pre = tmp tmp = head return pre
JZ25 合并两个排序的链表
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: defMerge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode: ifnot pHead1 andnot pHead2:return ifnot pHead2: return pHead1 ifnot pHead1: return pHead2 if pHead1.val > pHead2.val: pHead1, pHead2 = pHead2, pHead1 #保持1链条头节点更小 pre = cur = pHead1 pHead1 = pHead1.next while pHead1 or pHead2: if pHead1 and (not pHead2 or pHead1.val <= pHead2.val): cur.next = pHead1 pHead1 = pHead1.next elif pHead2 and (not pHead1 or pHead1.val > pHead2.val): cur.next = pHead2 pHead2 = pHead2.next cur = cur.next return pre
JZ26 树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。(我们约定空树不是任意一个树的子结构)
1 2 3 4 5 6 7 8 9
classSolution: defrecur(self,a,b): #判断同根树b是否为a的子结构 ifnot b: returnTrue#如果b为空,则b过了叶层,返回True elifnot a or a.val != b.val: returnFalse#如果a为空b不为空,则a过了叶层b没有,返回False else: returnself.recur(a.left,b.left) andself.recur(a.right,b.right) #都不为空递归左右子树
defHasSubtree(self , pRoot1: TreeNode, pRoot2: TreeNode) -> bool: returnbool(pRoot1 and pRoot2) and (self.recur(pRoot1, pRoot2) or \ self.HasSubtree(pRoot1.left, pRoot2) orself.HasSubtree(pRoot1.right, pRoot2))
classSolution: # matrix类型为二维列表,需要返回列表 defprintMatrix(self, matrix): ifnot matrix: return [] l, r, t, b = 0, len(matrix[0])-1, 0, len(matrix)-1 res = [] i = j = 0 whileTrue: for j inrange(l,r+1): res.append(matrix[i][j]) t += 1 if t > b: break for i inrange(t,b+1): res.append(matrix[i][j]) r -= 1 if l > r: break for j inrange(r,l-1,-1): res.append(matrix[i][j]) b -= 1 if t > b: break for i inrange(b,t-1,-1): res.append(matrix[i][j]) l += 1 if l > r: break return res
JZ30 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。
classSolution: defIsPopOrder(self , pushV: List[int], popV: List[int]) -> bool: stk, i = [], 0 for num in pushV: stk.append(num) while stk and stk[-1] == popV[i]: stk.pop() i += 1 returnnot stk
classSolution: defVerifySquenceOfBST(self , sequence: List[int]) -> bool: #分治思想 ifnot sequence: returnFalse defrecur(sequence): n = len(sequence) if n <= 2: returnTrue p = 0 while sequence[p] < sequence[-1]: p += 1 m = p while sequence[p] > sequence[-1]: p += 1 return p == n-1and recur(sequence[:m]) and recur(sequence[m:n-1]) return recur(sequence)
classSolution: defMoreThanHalfNum_Solution(self , numbers: List[int]) -> int: res, cnt = -1, 0 for num in numbers:#抵消法 if cnt == 0: res = num if num == res: cnt += 1 else: cnt -= 1 return res
JZ40 最小的K个数
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
1 2 3 4 5 6 7 8 9
#堆 import heapq classSolution: defGetLeastNumbers_Solution(self , input: List[int], k: int) -> List[int]: res = [] heapq.heapify(input) for _ inrange(k): res.append(heapq.heappop(input)) return res
#暴力求解 时间 nlog_10(n) 空间 1 classSolution: defNumberOf1Between1AndN_Solution(self, n): res = 0 for num inrange(1,n+1): while num: if num % 10 == 1: res += 1 num //= 10 return res
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#数位求解 classSolution: defNumberOf1Between1AndN_Solution(self, n): digit, res = 1, 0 h, c, l = n//10, n%10, 0 while h or c: if c == 0: res += h * digit elif c == 1: res += h * digit + l + 1 else: res += (h+1) * digit l += c * digit c = h % 10 h //= 10 digit *= 10 return res
classSolution: defGetUglyNumber_Solution(self , index: int) -> int: if index == 0: return0 dp = [1] * (index) a = b = c = 0#三个指针对应乘2、3、5 for i inrange(1,index): n2, n3, n5 = 2*dp[a], 3*dp[b], 5*dp[c] dp[i] = min(n2, n3, n5) if dp[i] == n2: a += 1#说明没有其他情况更小,所以指针前进一位 if dp[i] == n3: b += 1 if dp[i] == n5: c += 1 return dp[-1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#哈希表 时间N,空间N classSolution: defFirstNotRepeatingChar(self , str: str) -> int: mp = {} for s instr: if s notin mp: mp[s] = 1 else: mp[s] += 1 for i inrange(len(str)): if mp[str[i]] == 1: return i return -1 #Counter 时间N,空间N from collections import Counter classSolution: defFirstNotRepeatingChar(self , str: str) -> int: cnt = Counter(str) for i inrange(len(str)): if cnt[str[i]] == 1: return i return -1
1 2 3 4 5 6 7 8
#暴力,时间N2,空间N,如果用哈希表储存位置的话,时间同样是N classSolution: defFirstNotRepeatingChar(self , str: str) -> int: rec = set() for i inrange(len(str)): ifstr[i] notinstr[i+1:] andstr[i] notin rec: return i else: rec.add(str[i]) return -1
JZ51 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007
classSolution: defGetNumberOfK(self , nums: List[int], k: int) -> int: iflen(nums) == 1: if nums[0] == k: return1 else: return0 l, r = 0, len(nums) - 1 while l <= r: m = (l+r) // 2 if nums[m] < k + 0.5: l = m+1 elif nums[m] > k + 0.5: r = m-1 j = l l, r = 0, len(nums) - 1 while l <= r: m = (l+r) // 2 if nums[m] < k - 0.5: l = m+1 elif nums[m] > k - 0.5: r = m-1 return j - l
JZ54 二叉搜索树的第k个节点
给定一棵结点数为n 二叉搜索树,请找出其中的第 k 小的TreeNode结点值。
1.返回第k小的节点值即可
2.不能查找的情况,如二叉树为空,则返回-1,或者k大于n等等,也返回-1
3.保证n个节点的值不一样
1 2 3 4 5 6 7 8 9 10 11 12
classSolution: defKthNode(self , proot: TreeNode, k: int) -> int: defdfs(root): nonlocal k, res ifnot root or k < 0: return dfs(root.left) k -= 1 if k == 0: res = root.val dfs(root.right) res = -1 dfs(proot) return res
classSolution: defTreeDepth(self , pRoot: TreeNode) -> int: defdfs(root): nonlocal res, dep ifnot root: res = max(res, dep) return dep += 1 dfs(root.left) dfs(root.right) dep -= 1 res = dep = 0 dfs(pRoot) return res
JZ56 数组中只出现一次的两个数字
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
1 2 3 4 5 6 7 8 9 10 11
classSolution: defFindNumsAppearOnce(self , nums: List[int]) -> List[int]: mp = {} for num in nums: if num in mp: del mp[num] else: mp[num] = 1 res = [] for num in mp.keys(): res.append(num) res.sort() return res
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#异或运算 classSolution: defFindNumsAppearOnce(self , nums: List[int]) -> List[int]: tmp = 0 for num in nums: tmp ^= num k = 1 while k & tmp == 0: k <<= 1 res = [0, 0] for num in nums: if k & num: res[0] ^= num else: res[1] ^= num res.sort() return res
classSolution: defFindNumbersWithSum(self , array: List[int], sum: int) -> List[int]: i, j = 0, len(array)-1 while i < j: if array[i] + array[j] > sum: j -= 1 elif array[i] + array[j] < sum: i += 1 else: return [array[i],array[j]] return []
JZ58 左旋转字符串
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列 S ,请你把其循环左移 K 位后的序列输出。例如,字符序列 S = ”abcXYZdef” , 要求输出循环左移 3 位后的结果,即 “XYZdefabc”
1 2 3 4 5
classSolution: defLeftRotateString(self , str: str, n: int) -> str: ifnotstr: return'' n = n % len(str) returnstr[n:] + str[:n]
JZ59 滑动窗口的最大值
给定一个长度为 n 的数组 num 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
from collections import deque classSolution: defmaxInWindows(self , num: List[int], size: int) -> List[int]: if size == 0: return que = deque() res = [] i = j = 0 while j < len(num): while que and que[-1] < num[j]: que.pop() ifnot que or que[-1] >= num[j]: que.append(num[j]) if j >= size-1: res.append(que[0]) if que[0] == num[i]: que.popleft() i += 1 j += 1 return res
classSolution: defIsContinuous(self , numbers: List[int]) -> bool: lst = [] for num in numbers: if num != 0: lst.append(num) iflen(set(lst)) < len(lst): returnFalse ifmax(lst) - min(lst) > 4: returnFalse returnTrue
JZ62 孩子们的游戏(圆圈中最后剩下的数)
每年六一儿童节,牛客都会准备一些小礼物和小游戏去看望孤儿院的孩子们。其中,有个游戏是这样的:首先,让 n 个小朋友们围成一个大圈,小朋友们的编号是0~n-1。然后,随机指定一个数 m ,让编号为0的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0… m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客礼品,请你试着想下,哪个小朋友会得到这份礼品呢?
1 2 3 4 5 6
classSolution: defLastRemaining_Solution(self , n: int, m: int) -> int: x = 0#约瑟夫环 for i inrange(2,n+1): #第i次代表第i个小朋友 x = (x + m) % i return x
#暴力 classSolution: defmultiply(self , A: List[int]) -> List[int]: n = len(A) B = [1] * n for i inrange(n): for j inrange(n): if j != i: B[i] *= A[j] return B
1 2 3 4 5 6 7 8 9 10 11
#上下三角 classSolution: defmultiply(self , A: List[int]) -> List[int]: n = len(A) B = [1] * n for i inrange(1,n): B[i] = B[i-1] * A[i-1] for i inrange(n-2,-1,-1): B[i] *= A[i+1] A[i] *= A[i+1] return B
classSolution: defjumpFloorII(self , number: int) -> int: dp = [0] * (number+1) dp[0] = 1 for i inrange(1,number+1): for j inrange(i): dp[i] += dp[j] return dp[-1]
JZ73 翻转单词序列
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“nowcoder. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a nowcoder.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
#暴力 classSolution: defFindContinuousSequence(self , sum: int) -> List[List[int]]: res = [] for i inrange(1, sum//2 + 1): s = sum lst = [] while s > 0: lst.append(i) s -= i i += 1 if s == 0: res.append(lst) return res
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#滑动窗口 classSolution: defFindContinuousSequence(self , sum: int) -> List[List[int]]: res = [] i, j = 1, 2 r = sum//2 + 1 while i <= r and j <= r: s = (i+j)*(j+1-i)//2 if s == sum: res.append([_ for _ inrange(i,j+1)]) i += 1 elif j <= r-1and s < sum: j += 1 else: i += 1 return res
#自下而上 classSolution: defIsBalanced_Solution(self , pRoot: TreeNode) -> bool: defheight(pRoot): ifnot pRoot: return0 left = height(pRoot.left) if left < 0: return -1 right = height(pRoot.right) if right < 0: return -1 return -1ifabs(left-right)>1else1 + max(left,right) return height(pRoot) != -1
JZ81 调整数组顺序使奇数位于偶数前面(二)
输入一个长度为 n 整数数组,数组里面可能含有相同的元素,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,对奇数和奇数,偶数和偶数之间的相对位置不做要求,但是时间复杂度和空间复杂度必须如下要求。
1 2 3 4 5 6 7 8
classSolution: defreOrderArrayTwo(self , array: List[int]) -> List[int]: i, j = 0, len(array)-1 while i < j: while i < j and array[i] % 2 == 1: i += 1 while i < j and array[j] % 2 == 0: j -= 1 array[i], array[j] = array[j], array[i] return array
JZ83 剪绳子(进阶版)
给你一根长度为 n 的绳子,请把绳子剪成整数长的 m 段( m 、 n 都是整数, n > 1 并且 m > 1 , m <= n ),每段绳子的长度记为 k[1],…,k[m] 。请问 k[1]k[2]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是 8 时,我们把它剪成长度分别为 2、3、3 的三段,此时得到的最大乘积是 18 。
由于答案过大,请对 998244353 取模。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#快速幂 classSolution: defcutRope(self , number: int) -> int: if number <= 3: return number - 1
defquickpow(a, b): res = 1 while b: if b % 2: res = res * a % 998244353 b >>= 1 a = a*a % 998244353 return res
x, y = number // 3, number % 3 if y == 0: return quickpow(3,x) elif y == 1: return quickpow(3,x-1) * 4 % 998244353 else: return quickpow(3,x) * 2 % 998244353