* [1. 字符串组合](#1-字符串组合) * [2. 整数组合求和](#2-整数组合求和) * [3. 数组中重复的数字](#3-数组中重复的数字) * [4. 二维数组中的查找](#4-二维数组中的查找) * [5. 替换空格](#5-替换空格) * [6. 从尾到头打印链表](#6-从尾到头打印链表) * [7. 重建二叉树](#7-重建二叉树) * [8. 二叉树的下一个结点](#8-二叉树的下一个结点) * [9. 用两个栈实现队列](#9-用两个栈实现队列) * [10.1 斐波那契数列](#101-斐波那契数列) * [10.2 跳台阶](#102-跳台阶) * [10.3 矩形覆盖](#103-矩形覆盖) * [10.4 变态跳台阶](#104-变态跳台阶) * [11. 旋转数组的最小数字](#11-旋转数组的最小数字) * [12. 矩阵中的路径](#12-矩阵中的路径) * [13. 机器人的运动范围](#13-机器人的运动范围) * [14. 剪绳子](#14-剪绳子) * [15. 二进制中 1 的个数](#15-二进制中-1-的个数) * [16. 数值的整数次方](#16-数值的整数次方) * [17. 打印从 1 到最大的 n 位数](#17-打印从-1-到最大的-n-位数) * [18.1 在 O(1) 时间内删除链表节点](#181-在-o1-时间内删除链表节点) * [18.2 删除链表中重复的结点](#182-删除链表中重复的结点) * [19. 正则表达式匹配](#19-正则表达式匹配) * [20. 表示数值的字符串](#20-表示数值的字符串) * [21. 调整数组顺序使奇数位于偶数前面](#21-调整数组顺序使奇数位于偶数前面) * [22. 链表中倒数第 K 个结点](#22-链表中倒数第-k-个结点) * [23. 链表中环的入口结点](#23-链表中环的入口结点) * [24. 反转链表](#24-反转链表) * [25. 合并两个排序的链表](#25-合并两个排序的链表) * [26. 树的子结构](#26-树的子结构) * [27. 二叉树的镜像](#27-二叉树的镜像) * [参考文献](#参考文献) # 1. 字符串组合 ## 题目描述 给定三种类型的小球P、Q、R,每种小球的数量分别为np、nq、nr个。现在想讲这些小球排成一条直线,但是不允许相同类型的小球相邻,问有多少种排序方法。 如若np=2,nq=1,nr=1则共有6种排列方式:PQRP、QPRP、PRQP、PRPQ、RPQP以及PQPR。如果无法组合出合适的结果,则输出0. ### 输入 ```code 一行以空格相隔的三个数,分别表示为np、nq、nr。 ``` ### 输出 ```code 排列方法的数量。 ``` ### 样例输入 ```code 2 1 1 ``` ### 样例输出 ```code 6 ``` ## 解题思路 本题采用一种比较直接的方式进行解题,分为如下步骤: 1. 求解给定P、Q、R个数的时候的全排列,提供`Python`提供的`itertools.permutations`来实现,此时肯定有很多重复。 2. 去掉重复的情况,通过`Python`提供的`set`来实现。 3. 通过遍历找出相邻元素重复的串。 4. 求两个集合的差集,即为答案。 ```python import itertools np, nq, nr = [int(k) for k in raw_input().split(" ")] count = 0 result = [] for i in itertools.permutations("P"*np + "Q"*nq + "R"*nr,np + nq + nr): result.append(''.join(i)) result_same = [] for element in list(set(result)): for j in range(1, len(element)): if element[j-1] == element[j]: result_same.append(element) ret_list = list(set(result)^set(result_same)) print len(ret_list) ``` # 2. 整数组合求和 ## 题目描述 小米之家是成人糖果店。里面有很多便宜,好用,好玩的产品。中秋节到了,小米之家想给米粉准备一些固定金额大礼包。对于给定的一个金额,需要判断能不能用 不同种产品(一种产品在礼包最多出现一次)组合出来这个金额。聪明的你来帮帮米家的小伙伴吧。 ### 输入 ```code 输入N(N是正整数, N < = 200) 输入N个价格p(正整数, p <= 10000)用单空格分割 输入金额M(M是正整数,M <= 100000) ``` ### 输出 ```code 能组合出来输出1 否则输出0 ``` ### 样例输入 ```code 6 99 199 1999 10000 39 1499 10238 ``` ### 样例输出 ```code 1 ``` ## 解题思路 本题采用一种比较直接的方式进行解题,分为如下步骤: 1. 对输入np进行排序,方便后面快速结束。 2. 求解给定np时候的0~n个组合的和,提供`Python`提供的`itertools.permutations`来实现。 3. 如果较小的数相加已经大于目标,可以提前跳出本次循环。 ```python import itertools n = int(raw_input()) np = [int(k) for k in raw_input().split(" ")] np.sort() sum_np = int(raw_input()) flag = 0 for i in range(n): for j in itertools.permutations(np, i): if sum(j) > sum_np: continue; if sum(j) == sum_np: flag = 1; break; print flag ``` # 3. 数组中重复的数字 [NowCoder](https://www.nowcoder.com/practice/623a5ac0ea5b4e5f95552655361ae0a8?tpId=13&tqId=11203&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组 {2, 3, 1, 0, 2, 5},那么对应的输出是第一个重复的数字 2。 要求复杂度为 O(N) + O(1),也就是时间复杂度 O(N),空间复杂度 O(1)。因此不能使用排序的方法,也不能使用额外的标记数组。牛客网讨论区这一题的首票答案使用 nums[i] + length 来将元素标记,这么做会有加法溢出问题。 ## 解题思路 这种数组元素在 [0, n-1] 范围内的问题,可以将值为 i 的元素放到第 i 个位置上。 以 (2, 3, 1, 0, 2, 5) 为例: ```text-html-basic position-0 : (2,3,1,0,2,5) // 2 <-> 1 (1,3,2,0,2,5) // 1 <-> 3 (3,1,2,0,2,5) // 3 <-> 0 (0,1,2,3,2,5) // already in position position-1 : (0,1,2,3,2,5) // already in position position-2 : (0,1,2,3,2,5) // already in position position-3 : (0,1,2,3,2,5) // already in position position-4 : (0,1,2,3,2,5) // nums[i] == nums[nums[i]], exit ``` 遍历到位置 4 时,该位置上的数为 2,但是第 2 个位置上已经有一个 2 的值了,因此可以知道 2 重复。 ```java public boolean duplicate(int[] nums, int length, int[] duplication) { if (nums == null || length <= 0) return false; for (int i = 0; i < length; i++) { while (nums[i] != i) { if (nums[i] == nums[nums[i]]) { duplication[0] = nums[i]; return true; } swap(nums, i, nums[i]); } } return false; } private void swap(int[] nums, int i, int j) { int t = nums[i]; nums[i] = nums[j]; nums[j] = t; } ``` ```python nums = [int(k) for k in raw_input().split(" ")] print nums def duplicate(nums): if len(nums) <= 0: return -1, False for i in range(len(nums)): while nums[i] != i: if nums[i] == nums[nums[i]]: return nums[i], True index = nums[i] nums[i], nums[index] = nums[index], nums[i] # nums[i], nums[nums[i]] = nums[nums[i]], nums[i] return -1, False print duplicate(nums) ``` # 4. 二维数组中的查找 [NowCoder](https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqId=11154&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 ```html Consider the following matrix: [ [1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30] ] Given target = 5, return true. Given target = 20, return false. ``` ## 解题思路 从右上角开始查找。矩阵中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间。 复杂度:O(M + N) + O(1) 当前元素的查找区间为左下角的所有元素,例如元素 12 的查找区间如下:

```java public boolean Find(int target, int[][] matrix) { if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false; int rows = matrix.length, cols = matrix[0].length; int r = 0, c = cols - 1; // 从右上角开始 while (r <= rows - 1 && c >= 0) { if (target == matrix[r][c]) return true; else if (target > matrix[r][c]) r++; else c--; } return false; } ``` ```python target = int(input()) # nums = [[1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30]] nums = eval(input()) def find(target, matrix): if len(matrix) == 0 or len(matrix[0]) == 0: return False rows, cols = len(matrix), len(matrix[0]) r, c = 0, cols - 1 while r <= rows - 1 and c >= 0: if target == matrix[r][c]: return True elif target > matrix[r][c]: r += 1 else: c -= 1 return False print (find(target, nums)) ``` # 5. 替换空格 [NowCoder](https://www.nowcoder.com/practice/4060ac7e3e404ad1a894ef3e17650423?tpId=13&tqId=11155&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 将一个字符串中的空格替换成 "%20"。 ```text Input: "We Are Happy" Output: "We%20Are%20Happy" ``` ## 解题思路 在字符串尾部填充任意字符,使得字符串的长度等于替换之后的长度。因为一个空格要替换成三个字符(%20),因此当遍历到一个空格时,需要在尾部填充两个任意字符。 令 P1 指向字符串原来的末尾位置,P2 指向字符串现在的末尾位置。P1 和 P2从后向前遍历,当 P1 遍历到一个空格时,就需要令 P2 指向的位置依次填充 02%(注意是逆序的),否则就填充上 P1 指向字符的值。 从后向前遍是为了在改变 P2 所指向的内容时,不会影响到 P1 遍历原来字符串的内容。 ```java public String replaceSpace(StringBuffer str) { int P1 = str.length() - 1; for (int i = 0; i < P1 + 1; i++) if (str.charAt(i) == ' ') str.append(" "); int P2 = str.length() - 1; while (P1 >= 0 && P2 > P1) { char c = str.charAt(P1--); if (c == ' ') { str.setCharAt(P2--, '0'); str.setCharAt(P2--, '2'); str.setCharAt(P2--, '%'); } else { str.setCharAt(P2--, c); } } return str.toString(); } ``` ```python target = input() print (target.replace(" ", "%20")) ``` # 6. 从尾到头打印链表 [NowCoder](https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tqId=11156&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 输入链表的第一个节点,从尾到头反过来打印出每个结点的值。

## 解题思路 ### 使用栈 ```java public ArrayList printListFromTailToHead(ListNode listNode) { Stack stack = new Stack<>(); while (listNode != null) { stack.add(listNode.val); listNode = listNode.next; } ArrayList ret = new ArrayList<>(); while (!stack.isEmpty()) ret.add(stack.pop()); return ret; } ``` ### 使用递归 ```java public ArrayList printListFromTailToHead(ListNode listNode) { ArrayList ret = new ArrayList<>(); if (listNode != null) { ret.addAll(printListFromTailToHead(listNode.next)); ret.add(listNode.val); } return ret; } ``` ### 使用头插法 利用链表头插法为逆序的特点。 头结点和第一个节点的区别: - 头结点是在头插法中使用的一个额外节点,这个节点不存储值; - 第一个节点就是链表的第一个真正存储值的节点。 ```java public ArrayList printListFromTailToHead(ListNode listNode) { // 头插法构建逆序链表 ListNode head = new ListNode(-1); while (listNode != null) { ListNode memo = listNode.next; listNode.next = head.next; head.next = listNode; listNode = memo; } // 构建 ArrayList ArrayList ret = new ArrayList<>(); head = head.next; while (head != null) { ret.add(head.val); head = head.next; } return ret; } ``` ### 使用 Collections.reverse() ```java public ArrayList printListFromTailToHead(ListNode listNode) { ArrayList ret = new ArrayList<>(); while (listNode != null) { ret.add(listNode.val); listNode = listNode.next; } Collections.reverse(ret); return ret; } ``` ```python def printListFromTailToHead(listNode): # write code here l = list() while listNode: l.append(listNode.val) listNode = listNode.next l.reverse() return l ``` # 7. 重建二叉树 [NowCoder](https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 根据二叉树的前序遍历和中序遍历的结果,重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 ```html preorder = [3,9,20,15,7] inorder = [9,3,15,20,7] ```

## 解题思路 前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。 ```java // 缓存中序遍历数组每个值对应的索引 private Map indexForInOrders = new HashMap<>(); public TreeNode reConstructBinaryTree(int[] pre, int[] in) { for (int i = 0; i < in.length; i++) indexForInOrders.put(in[i], i); return reConstructBinaryTree(pre, 0, pre.length - 1, 0); } private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL) { if (preL > preR) return null; TreeNode root = new TreeNode(pre[preL]); int inIndex = indexForInOrders.get(root.val); int leftTreeSize = inIndex - inL; root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL); root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1); return root; } ``` ```python # 返回构造的TreeNode根节点 def reConstructBinaryTree(self, pre, tin): # write code here if not pre or not tin: return None root = TreeNode(pre.pop(0)) index = tin.index(root.val) root.left = self.reConstructBinaryTree(pre, tin[:index]) root.right = self.reConstructBinaryTree(pre, tin[index + 1:]) return root ``` # 8. 二叉树的下一个结点 [NowCoder](https://www.nowcoder.com/practice/9023a0c988684a53960365b889ceaf5e?tpId=13&tqId=11210&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 ```java public class TreeLinkNode { int val; TreeLinkNode left = null; TreeLinkNode right = null; TreeLinkNode next = null; TreeLinkNode(int val) { this.val = val; } } ``` ## 解题思路 ① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;

② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。

```java public TreeLinkNode GetNext(TreeLinkNode pNode) { if (pNode.right != null) { TreeLinkNode node = pNode.right; while (node.left != null) node = node.left; return node; } else { while (pNode.next != null) { TreeLinkNode parent = pNode.next; if (parent.left == pNode) return parent; pNode = pNode.next; } } return null; } ``` ```python def GetNext(self, pNode): # write code here # pNode is None if not pNode: return pNode if pNode.right: node = pNode.right while node.left: node = node.left return node else: while pNode.next: parent = pNode.next if parent.left == pNode: return parent pNode = pNode.next # pNode not have the next node return None ``` # 9. 用两个栈实现队列 [NowCoder](https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6?tpId=13&tqId=11158&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。 ## 解题思路 in 栈用来处理入栈(push)操作,out 栈用来处理出栈(pop)操作。一个元素进入 in 栈之后,出栈的顺序被反转。当元素要出栈时,需要先进入 out 栈,此时元素出栈顺序再一次被反转,因此出栈顺序就和最开始入栈顺序是相同的,先进入的元素先退出,这就是队列的顺序。

```java Stack in = new Stack(); Stack out = new Stack(); public void push(int node) { in.push(node); } public int pop() throws Exception { if (out.isEmpty()) while (!in.isEmpty()) out.push(in.pop()); if (out.isEmpty()) throw new Exception("queue is empty"); return out.pop(); } ``` ```python # -*- coding:utf-8 -*- class Solution: def __init__(self): self.stack1 = [] self.stack2 = [] def push(self, node): # write code here self.stack1.append(node) def pop(self): # return xx if self.stack2 == []: while self.stack1: self.stack2.append(self.stack1.pop()) return self.stack2.pop() return self.stack2.pop() ``` # 10.1 斐波那契数列 [NowCoder](https://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tpId=13&tqId=11160&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 求斐波那契数列的第 n 项,n <= 39。

## 解题思路 如果使用递归求解,会重复计算一些子问题。例如,计算 f(10) 需要计算 f(9) 和 f(8),计算 f(9) 需要计算 f(8) 和 f(7),可以看到 f(8) 被重复计算了。

递归是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。 ```java public int Fibonacci(int n) { if (n <= 1) return n; int[] fib = new int[n + 1]; fib[1] = 1; for (int i = 2; i <= n; i++) fib[i] = fib[i - 1] + fib[i - 2]; return fib[n]; } ``` 考虑到第 i 项只与第 i-1 和第 i-2 项有关,因此只需要存储前两项的值就能求解第 i 项,从而将空间复杂度由 O(N) 降低为 O(1)。 ```java public int Fibonacci(int n) { if (n <= 1) return n; int pre2 = 0, pre1 = 1; int fib = 0; for (int i = 2; i <= n; i++) { fib = pre2 + pre1; pre2 = pre1; pre1 = fib; } return fib; } ``` 由于待求解的 n 小于 40,因此可以将前 40 项的结果先进行计算,之后就能以 O(1) 时间复杂度得到第 n 项的值了。 ```java public class Solution { private int[] fib = new int[40]; public Solution() { fib[1] = 1; fib[2] = 2; for (int i = 2; i < fib.length; i++) fib[i] = fib[i - 1] + fib[i - 2]; } public int Fibonacci(int n) { return fib[n]; } } ``` ```python # -*- coding:utf-8 -*- class Solution: def __init__(self): self.fib = [0,1] for i in range(2,40): self.fib.append(self.fib[i-1]+self.fib[i-2]) def Fibonacci(self, n): # write code here return self.fib[n] ``` # 10.2 跳台阶 [NowCoder](https://www.nowcoder.com/practice/8c82a5b80378478f9484d87d1c5f12a4?tpId=13&tqId=11161&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 ## 解题思路 ```java public int JumpFloor(int n) { if (n <= 2) return n; int pre2 = 1, pre1 = 2; int result = 1; for (int i = 2; i < n; i++) { result = pre2 + pre1; pre2 = pre1; pre1 = result; } return result; } ``` ```python # -*- coding:utf-8 -*- class Solution: def jumpFloor(self, number): # write code here if number == 0: return number pre1, pre2 = 1, 1 #result = 0 for i in range(number): pre1, pre2 = pre2, pre1+pre2 return pre1 ``` # 10.3 矩形覆盖 [NowCoder](https://www.nowcoder.com/practice/72a5a919508a4251859fb2cfb987a0e6?tpId=13&tqId=11163&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 我们可以用 2\*1 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 2\*1 的小矩形无重叠地覆盖一个 2\*n 的大矩形,总共有多少种方法? ## 解题思路 ```java public int RectCover(int n) { if (n <= 2) return n; int pre2 = 1, pre1 = 2; int result = 0; for (int i = 3; i <= n; i++) { result = pre2 + pre1; pre2 = pre1; pre1 = result; } return result; } ``` ```python # -*- coding:utf-8 -*- class Solution: def rectCover(self, number): # write code here if number == 0: return number pre1, pre2 = 1, 1 #result = 0 for i in range(number): pre1, pre2 = pre2, pre1+pre2 return pre1 ``` # 10.4 变态跳台阶 [NowCoder](https://www.nowcoder.com/practice/22243d016f6b47f2a6928b4313c85387?tpId=13&tqId=11162&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级... 它也可以跳上 n 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 ## 解题思路 ```java public int JumpFloorII(int target) { int[] dp = new int[target]; Arrays.fill(dp, 1); for (int i = 1; i < target; i++) for (int j = 0; j < i; j++) dp[i] += dp[j]; return dp[target - 1]; } ``` ```python # -*- coding:utf-8 -*- class Solution: def jumpFloorII(self, number): # write code here if number <= 0: return 0 return pow(2, number-1) ``` # 11. 旋转数组的最小数字 [NowCoder](https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=13&tqId=11159&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组 {3, 4, 5, 1, 2} 为 {1, 2, 3, 4, 5} 的一个旋转,该数组的最小值为 1。 ## 解题思路 在一个有序数组中查找一个元素可以用二分查找,二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度都为 O(logN)。 本题可以修改二分查找算法进行求解: - 当 nums[m] <= nums[h] 的情况下,说明解在 [l, m] 之间,此时令 h = m; - 否则解在 [m + 1, h] 之间,令 l = m + 1。 ```java public int minNumberInRotateArray(int[] nums) { if (nums.length == 0) return 0; int l = 0, h = nums.length - 1; while (l < h) { int m = l + (h - l) / 2; if (nums[m] <= nums[h]) h = m; else l = m + 1; } return nums[l]; } ``` 如果数组元素允许重复的话,那么就会出现一个特殊的情况:nums[l] == nums[m] == nums[h],那么此时无法确定解在哪个区间,需要切换到顺序查找。例如对于数组 {1,1,1,0,1},l、m 和 h 指向的数都为 1,此时无法知道最小数字 0 在哪个区间。 ```java public int minNumberInRotateArray(int[] nums) { if (nums.length == 0) return 0; int l = 0, h = nums.length - 1; while (l < h) { int m = l + (h - l) / 2; if (nums[l] == nums[m] && nums[m] == nums[h]) return minNumber(nums, l, h); else if (nums[m] <= nums[h]) h = m; else l = m + 1; } return nums[l]; } private int minNumber(int[] nums, int l, int h) { for (int i = l; i < h; i++) if (nums[i] > nums[i + 1]) return nums[i + 1]; return nums[l]; } ``` ```python # -*- coding:utf-8 -*- class Solution: def minNumberInRotateArray(self, rotateArray): # write code here if len(rotateArray) == 0: return 0 return min(rotateArray) ``` # 12. 矩阵中的路径 [NowCoder](https://www.nowcoder.com/practice/c61c6999eecb4b8f88a98f66b273a3cc?tpId=13&tqId=11218&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如下面的矩阵包含了一条 bfce 路径。

## 解题思路 ```java private final static int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; private int rows; private int cols; public boolean hasPath(char[] array, int rows, int cols, char[] str) { if (rows == 0 || cols == 0) return false; this.rows = rows; this.cols = cols; boolean[][] marked = new boolean[rows][cols]; char[][] matrix = buildMatrix(array); for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) if (backtracking(matrix, str, marked, 0, i, j)) return true; return false; } private boolean backtracking(char[][] matrix, char[] str, boolean[][] marked, int pathLen, int r, int c) { if (pathLen == str.length) return true; if (r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] != str[pathLen] || marked[r][c]) return false; marked[r][c] = true; for (int[] n : next) if (backtracking(matrix, str, marked, pathLen + 1, r + n[0], c + n[1])) return true; marked[r][c] = false; return false; } private char[][] buildMatrix(char[] array) { char[][] matrix = new char[rows][cols]; for (int i = 0, idx = 0; i < rows; i++) for (int j = 0; j < cols; j++) matrix[i][j] = array[idx++]; return matrix; } ``` ```python # -*- coding:utf-8 -*- class Solution: def hasPath(self, matrix, rows, cols, path): # write code here for i in range(rows): for j in range(cols): if matrix[i*cols+j] == path[0]: if self.find(list(matrix),rows,cols,path[1:],i,j): return True return False def find(self,matrix,rows,cols,path,i,j): if not path: return True matrix[i*cols+j]='0' if j+1=0 and matrix[i*cols+j-1]==path[0]: return self.find(matrix,rows,cols,path[1:],i,j-1) elif i+1=0 and matrix[(i-1)*cols+j]==path[0]: return self.find(matrix,rows,cols,path[1:],i-1,j) else: return False def buildMatrix(self, matrix): array = [[0]*self.cols for i in range(self.rows)] for i in range(self.rows): idx = 0 for j in range(self.cols): array[i][j] = matrix[idx] idx += 1 return array ``` # 13. 机器人的运动范围 [NowCoder](https://www.nowcoder.com/practice/6e5207314b5241fb83f2329e89fdecc8?tpId=13&tqId=11219&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 地上有一个 m 行和 n 列的方格。一个机器人从坐标 (0, 0) 的格子开始移动,每一次只能向左右上下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 k 的格子。 例如,当 k 为 18 时,机器人能够进入方格 (35,37),因为 3+5+3+7=18。但是,它不能进入方格 (35,37),因为 3+5+3+8=19。请问该机器人能够达到多少个格子? ## 解题思路 ```java private static final int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; private int cnt = 0; private int rows; private int cols; private int threshold; private int[][] digitSum; public int movingCount(int threshold, int rows, int cols) { this.rows = rows; this.cols = cols; this.threshold = threshold; initDigitSum(); boolean[][] marked = new boolean[rows][cols]; dfs(marked, 0, 0); return cnt; } private void dfs(boolean[][] marked, int r, int c) { if (r < 0 || r >= rows || c < 0 || c >= cols || marked[r][c]) return; marked[r][c] = true; if (this.digitSum[r][c] > this.threshold) return; cnt++; for (int[] n : next) dfs(marked, r + n[0], c + n[1]); } private void initDigitSum() { int[] digitSumOne = new int[Math.max(rows, cols)]; for (int i = 0; i < digitSumOne.length; i++) { int n = i; while (n > 0) { digitSumOne[i] += n % 10; n /= 10; } } this.digitSum = new int[rows][cols]; for (int i = 0; i < this.rows; i++) for (int j = 0; j < this.cols; j++) this.digitSum[i][j] = digitSumOne[i] + digitSumOne[j]; } ``` ```python # -*- coding:utf-8 -*- class Solution: def __init__(self): self.acc = 0 def movingCount(self, threshold, rows, cols): # write code here self.threshold = threshold self.rows = rows self.cols = cols self.board = [[0 for _ in range(cols)] for _ in range(rows)] self.traverse(0,0) return self.acc def block(self, r, c): s = sum(map(int,str(r)+str(c))) return s>self.threshold def traverse(self, r, c): if not (0<=r= 5 时,3(n - 3) - 2(n - 2) = n - 5 >= 0。因此把长度大于 5 的绳子切成两段,令其中一段长度为 3 可以使得两段的乘积最大。 ```java public int integerBreak(int n) { if (n < 2) return 0; if (n == 2) return 1; if (n == 3) return 2; int timesOf3 = n / 3; if (n - timesOf3 * 3 == 1) timesOf3--; int timesOf2 = (n - timesOf3 * 3) / 2; return (int) (Math.pow(3, timesOf3)) * (int) (Math.pow(2, timesOf2)); } ``` ```python def integerBreak(n): if n < 2: return 0 if n == 2: return 1 if n == 3: return 2 timesOf3 = n // 3 if n - timesOf3 * 3 == 1: timesOf3 -= 1 timesOf2 = (n - timesOf3 * 3) // 2 return pow(3, timesOf3) * pow(2, timesOf2) ``` # 15. 二进制中 1 的个数 [NowCoder](https://www.nowcoder.com/practice/8ee967e43c2c4ec193b040ea7fbb10b8?tpId=13&tqId=11164&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 输入一个整数,输出该数二进制表示中 1 的个数。 ### n&(n-1) 该位运算去除 n 的位级表示中最低的那一位。 ``` n : 10110100 n-1 : 10110011 n&(n-1) : 10110000 ``` 时间复杂度:O(M),其中 M 表示 1 的个数。 ```java public int NumberOf1(int n) { int cnt = 0; while (n != 0) { cnt++; n &= (n - 1); } return cnt; } ``` ### Integer.bitCount() ```java public int NumberOf1(int n) { return Integer.bitCount(n); } ``` ```python # -*- coding:utf-8 -*- class Solution: def NumberOf1(self, n): # write code here if n<0: n=n&0xFFFFFFFF #把负号去掉,如果负号在后面会陷入死循环 return bin(n).count('1') ``` ```python # -*- coding:utf-8 -*- class Solution: def NumberOf1(self, n): # write code here return sum([(n>>i & 1) for i in range(0,32)]) ``` # 16. 数值的整数次方 [NowCoder](https://www.nowcoder.com/practice/1a834e5e3e1a4b7ba251417554e07c00?tpId=13&tqId=11165&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 给定一个 double 类型的浮点数 base 和 int 类型的整数 exponent,求 base 的 exponent 次方。 ## 解题思路 下面的讨论中 x 代表 base,n 代表 exponent。

因为 (x\*x)n/2 可以通过递归求解,并且每次递归 n 都减小一半,因此整个算法的时间复杂度为 O(logN)。 ```java public double Power(double base, int exponent) { if (exponent == 0) return 1; if (exponent == 1) return base; boolean isNegative = false; if (exponent < 0) { exponent = -exponent; isNegative = true; } double pow = Power(base * base, exponent / 2); if (exponent % 2 != 0) pow = pow * base; return isNegative ? 1 / pow : pow; } ``` ```python # -*- coding:utf-8 -*- class Solution: def Power(self, base, exponent): # write code here flag = 0 if base == 0: return False if exponent == 0: return 1 if exponent < 0: flag = 1 result = 1 for i in range(abs(exponent)): result *= base if flag == 1: result = 1 / result return result ``` ```python # -*- coding:utf-8 -*- class Solution: def Power(self, base, exponent): # write code here return pow(base, exponent) ``` ### 动态规划 ```java public int integerBreak(int n) { int[] dp = new int[n + 1]; dp[1] = 1; for (int i = 2; i <= n; i++) for (int j = 1; j < i; j++) dp[i] = Math.max(dp[i], Math.max(j * (i - j), dp[j] * (i - j))); return dp[n]; } ``` # 17. 打印从 1 到最大的 n 位数 ## 题目描述 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数即 999。 ## 解题思路 由于 n 可能会非常大,因此不能直接用 int 表示数字,而是用 char 数组进行存储。 使用回溯法得到所有的数。 ```java public void print1ToMaxOfNDigits(int n) { if (n <= 0) return; char[] number = new char[n]; print1ToMaxOfNDigits(number, 0); } private void print1ToMaxOfNDigits(char[] number, int digit) { if (digit == number.length) { printNumber(number); return; } for (int i = 0; i < 10; i++) { number[digit] = (char) (i + '0'); print1ToMaxOfNDigits(number, digit + 1); } } private void printNumber(char[] number) { int index = 0; while (index < number.length && number[index] == '0') index++; while (index < number.length) System.out.print(number[index++]); System.out.println(); } ``` ```python def numbersByRecursion(n,largest,result): def recursion(num,largest,result): if num <= largest: result.append(num) return recursion(num+1,largest,result) else: return result return recursion(n,largest,result) n = 2 result = [] largest = pow(10,n)-1 re = numbersByRecursion(1, largest, result) print (re) ``` # 18.1 在 O(1) 时间内删除链表节点 ## 解题思路 ① 如果该节点不是尾节点,那么可以直接将下一个节点的值赋给该节点,然后令该节点指向下下个节点,再删除下一个节点,时间复杂度为 O(1)。

② 否则,就需要先遍历链表,找到节点的前一个节点,然后让前一个节点指向 null,时间复杂度为 O(N)。

综上,如果进行 N 次操作,那么大约需要操作节点的次数为 N-1+N=2N-1,其中 N-1 表示 N-1 个不是尾节点的每个节点以 O(1) 的时间复杂度操作节点的总次数,N 表示 1 个尾节点以 O(N) 的时间复杂度操作节点的总次数。(2N-1)/N \~ 2,因此该算法的平均时间复杂度为 O(1)。 ```java public ListNode deleteNode(ListNode head, ListNode tobeDelete) { if (head == null || head.next == null || tobeDelete == null) return null; if (tobeDelete.next != null) { // 要删除的节点不是尾节点 ListNode next = tobeDelete.next; tobeDelete.val = next.val; tobeDelete.next = next.next; } else { ListNode cur = head; while (cur.next != tobeDelete) cur = cur.next; cur.next = null; } return head; } ``` ### 动态规划 ```java public int integerBreak(int n) { int[] dp = new int[n + 1]; dp[1] = 1; for (int i = 2; i <= n; i++) for (int j = 1; j < i; j++) dp[i] = Math.max(dp[i], Math.max(j * (i - j), dp[j] * (i - j))); return dp[n]; } ``` ```python class ListNode: def __init__(self, x = None): self.val = x self.next = None def __del__(self): self.val = None self.next = None class Solution: def list_generate(self, lst): """ 生成链表 """ if not lst: return None list_node = ListNode() list_node.value = lst[0] if len(lst) == 1: list_node.next_node = None else: list_node.next_node = self.list_generate(lst[1:]) return list_node def find_node(self, node, target_value): """ 根据给定的目标值,找出指定节点的位置 非题目要求,只是为了测试验证 """ if not target_value: return False while node: if node.value == target_value: return node node = node.next_node return False def delete_node(self, head_node, del_node): """ 删除指定节点 """ if not (head_node and del_node): return False if del_node.next_node: # 删除的节点不是尾节点,而且不是唯一一个节点 del_next_node = del_node.next_node del_node.value = del_next_node.value del_node.next_node = del_next_node.next_node del_next_node.__del__() del_next_node.__del__() elif del_node == head_node: # 唯一一个节点,删除头节点 head_node = None del_node = None else: # 删除节点为尾节点 node = head_node while node.next_node != del_node: node = node.next_node node.next_node = None del_node = None return head_node if __name__ == '__main__': solution = Solution() head_node = solution.list_generate(['a', 'b', 'c', 'e', 'd', 'd']) target_value = 'a' target_node = solution.find_node(head_node, target_value) if target_node: print (target_node.value) head_node = solution.delete_node(head_node, target_node) node = head_node if node: while node: print (node.value) node = node.next_node if node: print ('->') else: print ('wrong') ``` # 18.2 删除链表中重复的结点 [NowCoder](https://www.nowcoder.com/practice/fc533c45b73a41b0b44ccba763f866ef?tpId=13&tqId=11209&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述

## 解题描述 ```java public ListNode deleteDuplication(ListNode pHead) { if (pHead == null || pHead.next == null) return pHead; ListNode next = pHead.next; if (pHead.val == next.val) { while (next != null && pHead.val == next.val) next = next.next; return deleteDuplication(next); } else { pHead.next = deleteDuplication(pHead.next); return pHead; } } ``` ```python # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def deleteDuplication(self, pHead): # write code here if not pHead or not pHead.next: return pHead next = pHead.next if pHead.val == next.val: while next and pHead.val == next.val: next = next.next return self.deleteDuplication(next) else: pHead.next = self.deleteDuplication(pHead.next) return pHead ``` # 19. 正则表达式匹配 [NowCoder](https://www.nowcoder.com/practice/45327ae22b7b413ea21df13ee7d6429c?tpId=13&tqId=11205&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 请实现一个函数用来匹配包括 '.' 和 '\*' 的正则表达式。模式中的字符 '.' 表示任意一个字符,而 '\*' 表示它前面的字符可以出现任意次(包含 0 次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串 "aaa" 与模式 "a.a" 和 "ab\*ac\*a" 匹配,但是与 "aa.a" 和 "ab\*a" 均不匹配。 ## 解题思路 应该注意到,'.' 是用来当做一个任意字符,而 '\*' 是用来重复前面的字符。这两个的作用不同,不能把 '.' 的作用和 '\*' 进行类比,从而把它当成重复前面字符一次。 ```java public boolean match(char[] str, char[] pattern) { int m = str.length, n = pattern.length; boolean[][] dp = new boolean[m + 1][n + 1]; dp[0][0] = true; for (int i = 1; i <= n; i++) if (pattern[i - 1] == '*') dp[0][i] = dp[0][i - 2]; for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) if (str[i - 1] == pattern[j - 1] || pattern[j - 1] == '.') dp[i][j] = dp[i - 1][j - 1]; else if (pattern[j - 1] == '*') if (pattern[j - 2] == str[i - 1] || pattern[j - 2] == '.') { dp[i][j] |= dp[i][j - 1]; // a* counts as single a dp[i][j] |= dp[i - 1][j]; // a* counts as multiple a dp[i][j] |= dp[i][j - 2]; // a* counts as empty } else dp[i][j] = dp[i][j - 2]; // a* only counts as empty return dp[m][n]; } ``` ```python # -*- coding:utf-8 -*- class Solution: # s, pattern都是字符串 def match(self, s, pattern): # write code here if (len(s) == 0 and len(pattern) == 0): return True if (len(s) > 0 and len(pattern) == 0): return False if (len(pattern) > 1 and pattern[1] == '*'): if (len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.')): return (self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern)) else: return self.match(s, pattern[2:]) if (len(s) > 0 and (pattern[0] == '.' or pattern[0] == s[0])): return self.match(s[1:], pattern[1:]) return False ``` ```python # -*- coding:utf-8 -*- import re class Solution: # s, pattern都是字符串 def match(self, s, pattern): # write code here if s == None or pattern == None: return False if s == "" and pattern == "": return True if pattern == "" and s != "": return False res = re.compile(str(pattern)+"$") result = res.match(str(s)) if result is None: return False else: return True ``` # 20. 表示数值的字符串 [NowCoder](https://www.nowcoder.com/practice/6f8c901d091949a5837e24bb82a731f2?tpId=13&tqId=11206&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 ```html true "+100" "5e2" "-123" "3.1416" "-1E-16" false "12e" "1a3.14" "1.2.3" "+-5" "12e+4.3" ``` ## 解题思路 使用正则表达式进行匹配。 ```html [] : 字符集合 () : 分组 ? : 重复 0 ~ 1 + : 重复 1 ~ n * : 重复 0 ~ n . : 任意字符 \\. : 转义后的 . \\d : 数字 ``` ```java public boolean isNumeric(char[] str) { if (str == null || str.length == 0) return false; return new String(str).matches("[+-]?\\d*(\\.\\d+)?([eE][+-]?\\d+)?"); } ``` ```python # -*- coding:utf-8 -*- import re class Solution: # s字符串 def isNumeric(self, s): # write code here return re.match('[+-]?\\d*(\\.\\d+)?([eE][+-]?\\d+)?$', s) ``` # 21. 调整数组顺序使奇数位于偶数前面 [NowCoder](https://www.nowcoder.com/practice/beb5aa231adc45b2a5dcc5b62c93f593?tpId=13&tqId=11166&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 需要保证奇数和奇数,偶数和偶数之间的相对位置不变,这和书本不太一样。 ## 解题思路 ```java public void reOrderArray(int[] nums) { // 奇数个数 int oddCnt = 0; for (int val : nums) if (val % 2 == 1) oddCnt++; int[] copy = nums.clone(); int i = 0, j = oddCnt; for (int num : copy) { if (num % 2 == 1) nums[i++] = num; else nums[j++] = num; } } ``` ```python # -*- coding:utf-8 -*- import copy class Solution: def reOrderArray(self, array): # write code here oddCnt = 0 for val in array: if val % 2 == 1: oddCnt += 1 copyArray = copy.deepcopy(array) i, j = 0, oddCnt for num in array: if num % 2 ==1: copyArray[i] = num i += 1 else: copyArray[j] = num j += 1 return copyArray ``` ```python # -*- coding:utf-8 -*- class Solution: def reOrderArray(self, array): # write code here odd = [x for x in array if x%2] even = [x for x in array if not (x%2)] result = odd + even return result ``` # 22. 链表中倒数第 K 个结点 [NowCoder](https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&tqId=11167&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 解题思路 设链表的长度为 N。设两个指针 P1 和 P2,先让 P1 移动 K 个节点,则还有 N - K 个节点可以移动。此时让 P1 和 P2 同时移动,可以知道当 P1 移动到链表结尾时,P2 移动到 N - K 个节点处,该位置就是倒数第 K 个节点。

```java public ListNode FindKthToTail(ListNode head, int k) { if (head == null) return null; ListNode P1 = head; while (P1 != null && k-- > 0) P1 = P1.next; if (k > 0) return null; ListNode P2 = head; while (P1 != null) { P1 = P1.next; P2 = P2.next; } return P2; } ``` ```python class Solution: def FindKthToTail(self, head, k): # write code here if head == None: return None p1 = head while p1 and k > 0: k -= 1 p1 = p1.next if k > 0: return None p2 = head while p1: p1 = p1.next p2 = p2.next return p2 ``` # 23. 链表中环的入口结点 [NowCoder](https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&tqId=11208&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述 一个链表中包含环,请找出该链表的环的入口结点。要求不能使用额外的空间。 ## 解题思路 使用双指针,一个指针 fast 每次移动两个节点,一个指针 slow 每次移动一个节点。因为存在环,所以两个指针必定相遇在环中的某个节点上。假设相遇点在下图的 y6 位置,此时 fast 移动的节点数为 x+2y+z,slow 为 x+y,由于 fast 速度比 slow 快一倍,因此 x+2y+z=2(x+y),得到 x=z。 在相遇点,slow 要到环的入口点还需要移动 z 个节点,如果让 fast 重新从头开始移动,并且速度变为每次移动一个节点,那么它到环入口点还需要移动 x 个节点。在上面已经推导出 x=z,因此 fast 和 slow 将在环入口点相遇。

```java public ListNode EntryNodeOfLoop(ListNode pHead) { if (pHead == null || pHead.next == null) return null; ListNode slow = pHead, fast = pHead; do { fast = fast.next.next; slow = slow.next; } while (slow != fast); fast = pHead; while (slow != fast) { slow = slow.next; fast = fast.next; } return slow; } ``` ```python class Solution: def EntryNodeOfLoop(self, pHead): # write code here if not pHead: return None plist = [] while True: plist.append(pHead) pHead = pHead.next if not pHead: return None if pHead in plist: return pHead ``` # 24. 反转链表 [NowCoder](https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=13&tqId=11168&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 解题思路 ### 递归 ```java public ListNode ReverseList(ListNode head) { if (head == null || head.next == null) return head; ListNode next = head.next; head.next = null; ListNode newHead = ReverseList(next); next.next = head; return newHead; } ``` ```python # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: # 返回ListNode def ReverseList(self, pHead): # write code here if pHead == None or pHead.next == None: return pHead next = pHead.next pHead.next = None newHead = self.ReverseList(next) next.next = pHead return newHead ``` ### 迭代 ```java public ListNode ReverseList(ListNode head) { ListNode newList = new ListNode(-1); while (head != null) { ListNode next = head.next; head.next = newList.next; newList.next = head; head = next; } return newList.next; } ``` ```python # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: # 返回ListNode def ReverseList(self, pHead): # write code here newList = ListNode(-1) while pHead: next = pHead.next pHead.next = newList.next newList.next = pHead pHead = next return newList.next ``` # 25. 合并两个排序的链表 [NowCoder](https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337?tpId=13&tqId=11169&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述

## 解题思路 ### 递归 ```java public ListNode Merge(ListNode list1, ListNode list2) { if (list1 == null) return list2; if (list2 == null) return list1; if (list1.val <= list2.val) { list1.next = Merge(list1.next, list2); return list1; } else { list2.next = Merge(list1, list2.next); return list2; } } ``` ```python # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: # 返回合并后列表 def Merge(self, pHead1, pHead2): # write code here if pHead1 == None: return pHead2 if pHead2 == None: return pHead1 if pHead1.val <= pHead2.val: pHead1.next = self.Merge(pHead1.next, pHead2) return pHead1 else: pHead2.next = self.Merge(pHead1, pHead2.next) return pHead2 ``` ### 迭代 ```java public ListNode Merge(ListNode list1, ListNode list2) { ListNode head = new ListNode(-1); ListNode cur = head; while (list1 != null && list2 != null) { if (list1.val <= list2.val) { cur.next = list1; list1 = list1.next; } else { cur.next = list2; list2 = list2.next; } cur = cur.next; } if (list1 != null) cur.next = list1; if (list2 != null) cur.next = list2; return head.next; } ``` ```python # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: # 返回合并后列表 def Merge(self, pHead1, pHead2): # write code here head = ListNode(-1) cur = head while pHead1 and pHead2: if pHead1.val <= pHead2.val: cur.next = pHead1 pHead1 = pHead1.next else: cur.next = pHead2 pHead2 = pHead2.next cur = cur.next if pHead1: cur.next = pHead1 if pHead2: cur.next = pHead2 return head.next ``` # 26. 树的子结构 [NowCoder](https://www.nowcoder.com/practice/6e196c44c7004d15b1610b9afca8bd88?tpId=13&tqId=11170&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述

## 解题思路 ```java public boolean HasSubtree(TreeNode root1, TreeNode root2) { if (root1 == null || root2 == null) return false; return isSubtreeWithRoot(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) { if (root2 == null) return true; if (root1 == null) return false; if (root1.val != root2.val) return false; return isSubtreeWithRoot(root1.left, root2.left) && isSubtreeWithRoot(root1.right, root2.right); } ``` ```python # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def HasSubtree(self, pRoot1, pRoot2): # write code here if pRoot1 == None or pRoot2 == None: return False return self.isSubtreeWithRoot(pRoot1, pRoot2) or \ self.HasSubtree(pRoot1.left, pRoot2) or \ self.HasSubtree(pRoot1.right, pRoot2) def isSubtreeWithRoot(self, pRoot1, pRoot2): if pRoot2 == None: return True if pRoot1 == None: return False if pRoot1.val != pRoot2.val: return False return self.isSubtreeWithRoot(pRoot1.left, pRoot2.left) and \ self.isSubtreeWithRoot(pRoot1.right, pRoot2.right) ``` # 27. 二叉树的镜像 [NowCoder](https://www.nowcoder.com/practice/564f4c26aa584921bc75623e48ca3011?tpId=13&tqId=11171&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) ## 题目描述

## 解题思路 ```java public void Mirror(TreeNode root) { if (root == null) return; swap(root); Mirror(root.left); Mirror(root.right); } private void swap(TreeNode root) { TreeNode t = root.left; root.left = root.right; root.right = t; } ``` ```python # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: # 返回镜像树的根节点 def Mirror(self, root): # write code here if root == None: return self.swap(root) self.Mirror(root.left) self.Mirror(root.right) def swap(self, root): root.left, root.right = root.right, root.left ``` # 参考文献 - 何海涛. 剑指 Offer[M]. 电子工业出版社, 2012.