剑指Offer刷题记录,共75题,陆续更新中
剑指 Offer(第 2 版) - 力扣(LeetCode)
找出数组中重复的数字。在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
1 2 3 输入: [2, 3, 1, 0, 2, 5, 3] 输出:2 或 3
方法:使用哈希集合的方法,如果出现重复就直接返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Offer03 { public static void main (String[] args) { int [] input = {2 , 3 , 1 , 0 , 2 , 5 , 3 }; System.out.println(findRepeatNumber(input)); } public static int findRepeatNumber (int [] nums) { HashSet<Integer> hashset = new HashSet <>(); for (int x:nums){ if (hashset.contains(x)) return x; else { hashset.add(x); } } return 0 ; } }
在一个 n * m 的二维数组中,每一行都按照从左到右 非递减 的顺序排序,每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
现有矩阵 matrix 如下:
1 2 3 4 5 6 7 [ [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] ]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
方法:对每一行使用二分查找,降低查询耗时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class Offer04 { public static void main (String[] args) { int [][] 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 }}; System.out.println(findNumberIn2DArray(matrix, 23 )); } public static boolean findNumberIn2DArray (int [][] matrix, int target) { for (int i = 0 ;i<matrix.length;i++){ if (binarySearch(matrix[i],target)){ return true ; } } return false ; } public static boolean binarySearch (int [] input,int target) { int low = 0 ; int high = input.length-1 ; while (low <= high){ int mid = (high-low)/2 +low; if (input[mid] == target){ return true ; }else if (input[mid] >target){ high = mid-1 ; }else { low = mid+1 ; } } return false ; } }
请实现一个函数,把字符串 s 中的每个空格替换成”%20”。
1 2 输入:s = "We are happy." 输出:"We%20are%20happy."
方法:直接调用库函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Offer05 { public static void main (String[] args) { String input = "We are happy." ; System.out.println(replaceSpace(input)); } public static String replaceSpace (String s) { return s.replace(" " ,"%20" ); } }
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
1 2 输入:head = [1,3,2] 输出:[2,3,1]
方法:用栈,先压栈再出栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Offer06 { public static void main (String[] args) { } public int [] reversePrint(ListNode head) { Stack<ListNode> stack = new Stack <>(); while (head != null ){ stack.push(head); head = head.next; } int [] val = new int [stack.size()]; int i = 0 ; while (!stack.isEmpty()){ val[i++] = stack.pop().val; } return val; } } class ListNode { int val; ListNode next; ListNode(int x) { val = x; } }
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
1 2 Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] Output: [3,9,20,null,null,15,7]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public class Offer07 { public static void main (String[] args) { int [] preorder = {3 ,9 ,20 ,15 ,7 }; int [] inorder = {9 ,3 ,15 ,20 ,7 }; System.out.println(buildTree(preorder, inorder)); System.out.println("finished" ); } public static TreeNode buildTree (int [] preorder, int [] inorder) { if (preorder.length == 0 ) return null ; if (preorder.length == 1 ){ return new TreeNode (preorder[0 ]); } TreeNode ROOT = new TreeNode (preorder[0 ]); int index = search(inorder,preorder[0 ]); TreeNode left = buildTree(Arrays.copyOfRange(preorder,1 ,index+1 ),Arrays.copyOfRange(inorder,0 ,index)); TreeNode right = buildTree(Arrays.copyOfRange(preorder,index+1 ,preorder.length),Arrays.copyOfRange(inorder,index+1 ,inorder.length)); ROOT.left = left; ROOT.right = right; return ROOT; } public static int search (int [] input,int target) { for (int i = 0 ;i<input.length;i++){ if (input[i] == target){ return i; } } return 0 ; } public static int binarySearch (int [] input,int target) { int low = 0 ; int high = input.length-1 ; while (low <= high){ int mid = (high-low)/2 +low; if (input[mid] == target){ return mid; }else if (input[mid] >target){ high = mid-1 ; }else { low = mid+1 ; } } return 0 ; } } class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } }
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1
1 2 3 4 输入: ["CQueue","appendTail","deleteHead","deleteHead","deleteHead"] [[],[3],[],[],[]] 输出:[null,null,3,-1,-1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Offer09 { public static void main (String[] args) { CQueue obj = new CQueue (); obj.appendTail(100 ); int param_2 = obj.deleteHead(); System.out.println(param_2); } static class CQueue { Stack<Integer> stack1 = new Stack <>(); Stack<Integer> stack2 = new Stack <>(); public CQueue () { } public void appendTail (int value) { stack1.clear(); while (!stack2.isEmpty()){ stack1.add(stack2.pop()); } stack1.add(value); while (!stack1.isEmpty()){ stack2.push(stack1.pop()); } } public int deleteHead () { if (stack2.isEmpty()){ return -1 ; }else { return stack2.pop(); } } } }
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Offer10_1 { public static void main (String[] args) { System.out.println(fib(100 )); } public static int fib (int n) { if (n<=1 ){return n;} int [] ans = new int [n+1 ]; ans[1 ] = 1 ; int i = 2 ; while (i<=n){ ans[i] = (ans[i-1 ]+ans[i-2 ]) % 1000000007 ; i+=1 ; } return ans[n]; } }
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Offer10_2 { public static void main (String[] args) { System.out.println(numWays(100 )); } public static int numWays (int n) { if (n==0 ){return 1 ;} if (n<=3 ){return n;} int [] ans = new int [n+1 ]; ans[0 ] = 1 ; ans[1 ] = 1 ; int i = 2 ; while (i<n+1 ){ ans[i] = (ans[i-1 ]+ans[i-2 ]) % 1000000007 ; i+=1 ; } return ans[n]; } }
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Offer11 { public static void main (String[] args) { } public int minArray (int [] numbers) { if (numbers.length == 1 ) return numbers[0 ]; for (int i = 0 ;i<=numbers.length-2 ;i++){ if (numbers[i+1 ] - numbers[i] < 0 ){ return numbers[i+1 ]; } } return numbers[0 ]; } }
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class Offer12 { public static void main (String[] args) { char [][] board = {{'A' ,'B' ,'C' ,'E' },{'S' ,'F' ,'C' ,'S' },{'A' ,'D' ,'E' ,'E' }}; String word = "ABCCED" ; System.out.println(exist(board, word)); } public static boolean exist (char [][] board, String word) { char [] wordArray = word.toCharArray(); for (int i = 0 ;i<board.length;i++){ for (int j = 0 ;j<board[0 ].length;j++){ if (dfs(board,wordArray,i,j,0 )) return true ; } } return false ; } public static boolean dfs (char [][] board,char [] wordArray,int i,int j,int k) { if (i>= board.length || j>= board[0 ].length || i<0 || j<0 || board[i][j] != wordArray[k]) return false ; if (k == wordArray.length-1 ) return true ; board[i][j] = '\0' ; boolean res = dfs(board,wordArray,i-1 ,j,k+1 ) || dfs(board,wordArray,i+1 ,j,k+1 ) ||dfs(board,wordArray,i,j-1 ,k+1 )||dfs(board,wordArray,i,j+1 ,k+1 ); board[i][j] = wordArray[k]; return res; } }
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
1 2 输入:m = 2, n = 3, k = 1 输出:3
构造一个辅助函数用于获取位数和,用一个二维的可见数组表示是否可见,在递推过程中判断可达的情况,vis[ij]的可达情况取决于vis[i-1,j]和vis[i,j-1]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public int movingCount (int m, int n, int k) { if (k == 0 ) { return 1 ; } boolean [][] vis = new boolean [m][n]; int ans = 1 ; vis[0 ][0 ] = true ; for (int i = 0 ;i<m;i++){ for (int j= 0 ;j<n;j++){ if ((i==0 && j==0 ) || get(i)+get(j) >k){ continue ; } if (i-1 >=0 ){ vis[i][j] |= vis[i-1 ][j]; } if (j-1 >=0 ){ vis[i][j] |= vis[i][j-1 ]; } if (vis[i][j]){ ans ++; } } } return ans; } private static int get (int x) { int res = 0 ; while (x != 0 ) { res += x % 10 ; x /= 10 ; } return res; } }
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1] …*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class Offer14_1 { public static void main (String[] args) { System.out.println(cuttingRope(58 )); } public static int cuttingRope (int n) { switch (n){ case 2 :return 1 ; case 3 :return 2 ; case 4 :return 4 ; case 5 :return 6 ; case 6 :return 9 ; default :return cuttingRope(n-3 )*3 ; } } public int cuttingRope2 (int n) { int [] dp = new int [n + 1 ]; for (int i = 2 ; i <= n; i++) { int curMax = 0 ; for (int j = 1 ; j < i; j++) { curMax = Math.max(curMax, Math.max(j * (i - j), j * dp[i - j])); } dp[i] = curMax; } return dp[n]; } }
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1] 。请问 k[0]k[1] …*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Offer14_2 { public static void main (String[] args) { System.out.println(cuttingRope(100 )); } public static int cuttingRope (int n) { if (n <= 3 ) return n-1 ; int p = 1000000007 ; int b = n%3 ; long rem = 1 , x = 3 ; for (int a = n / 3 - 1 ; a > 0 ; a /= 2 ){ if (a % 2 == 1 ) rem = (rem * x) % p; x = (x * x) % p; } if (b == 0 ) return (int )(rem * 3 % p); if (b == 1 ) return (int )(rem * 4 % p); return (int )(rem * 6 % p); } }
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。
提示:请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 在 Java 中,编译器使用 二进制补码 记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Offer15 { public static void main (String[] args) { System.out.println(hammingWeight1(114514 )); } public static int hammingWeight (int n) { int count = 0 ; for (int i = 0 ;i<32 ;i++){ int k = 1 <<i; if ((n & 1 <<i) !=0 ){ count++; } } return count; } public static int hammingWeight1 (int n) { int ret = 0 ; while (n != 0 ) { n &= n - 1 ; ret++; } return ret; } }
实现 pow(x , n ) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class Offer16 { public static void main (String[] args) { System.out.println(myPow(2.00000 , -2147483648 )); } public static double myPow (double x, int n) { return myPowhelper(x,n); } public static double myPowhelper (double x, long n) { if (n == 0 || x == 1.0 ) return 1.0 ; if (n == 1 ) return x; if (n<0 ) { return myPowhelper(1 /x,-n); } double ans = 1.0 ; HashMap<Long,Double> map = new HashMap <>(); map.put(1L ,x); Long n1 = 1L ; while (n1<=n/2 ){ map.put(n1*2L ,map.get(n1)*map.get(n1)); n1*=2 ; } while (n>0 ){ if ((n / n1) == 0 ){ n1/=2L ; continue ; } ans *= map.get(n1); n -= n1; n1 /= 2L ; } return ans; } }
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Offer17 { public static void main (String[] args) { System.out.println(Arrays.toString(printNumbers(2 ))); } public static int [] printNumbers(int n) { int max = (int )Math.pow(10 ,n); int [] result = new int [max-1 ]; int i = 1 ; while (i<max){ result[i-1 ] = i; i++; } return result; } }
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Offer18 { public static void main (String[] args) { } public static ListNode deleteNode (ListNode head, int val) { ListNode dummy = head; if (dummy.val== val) return head.next; while (dummy.next != null ){ if (dummy.next.val == val){ dummy.next = dummy.next.next; return head; } dummy = dummy.next; } return head; } static class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } }
请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.’表示任意一个字符,而’ ‘表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”abac a”匹配,但与”aa.a”和”ab*a”均不匹配。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class Offer19 { public static void main (String[] args) { System.out.println(isMatch("aab" , "c*a*b" )); } public static boolean isMatch (String s, String p) { boolean [][] dp = new boolean [s.length()+1 ][p.length()+1 ]; dp[0 ][0 ] = true ; for (int i = 1 ;i<p.length()+1 ;i++){ if (p.charAt(i-1 ) == '*' ){ dp[0 ][i] = dp[0 ][i-2 ]; } } for (int i = 1 ;i<s.length()+1 ;i++){ for (int j = 1 ;j<p.length()+1 ;j++){ if (s.charAt(i-1 ) == p.charAt(j-1 )||p.charAt(j - 1 ) == '.' ){ dp[i][j] = dp[i-1 ][j-1 ]; } else if (p.charAt(j - 1 ) == '*' ) { if (s.charAt(i-1 ) != p.charAt(j-2 )&& p.charAt(j-2 ) != '.' ){ dp[i][j] = dp[i][j-2 ]; }else { dp[i][j] = dp[i-1 ][j] | dp[i][j-2 ]; } } } } return dp[s.length()][p.length()]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution : def isMatch (self, s: str , p: str ) -> bool : m,n = len (s),len (p) dp = [[False ]* (n+1 ) for _ in range (m+1 )] dp[0 ][0 ] = True for j in range (1 ,n+1 ): if p[j-1 ] == '*' : dp[0 ][j] = dp[0 ][j-2 ] for i in range (1 ,m+1 ): for j in range (1 ,n+1 ): if s[i-1 ] == p[j-1 ] or p[j-1 ] == "." : dp[i][j] = dp[i-1 ][j-1 ] elif p[j-1 ] == "*" : if s[i-1 ] != p[j-2 ] and p[j-2 ] != '.' : dp[i][j] = dp[i][j-2 ] else : dp[i][j] = dp[i-1 ][j] | dp[i][j-2 ] return dp[m][n]
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
本题属于搞脑子的那种,严谨的做法太费力了,一下是一种取巧的做法,摘自leetcode题解。
trim函数去除首尾空格,用Double.parseDouble库函数帮助判断。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public boolean isNumber (String s) { if (s == null || s.length() == 0 ){ return false ; } s = s.trim(); try { double a = Double.parseDouble(s); }catch (Exception e){ return false ; } char c = s.charAt(s.length()-1 ); return (c >= '0' && c <= '9' ) || c == '.' ; } }
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。
1 2 3 输入:nums = [1,2,3,4] 输出:[1,3,2,4] 注:[3,1,2,4] 也是正确的答案之一。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class Offer21 { public static void main (String[] args) { int [] nums = {1 ,2 ,3 ,4 }; System.out.println(Arrays.toString(exchange(nums))); } public static int [] exchange(int [] nums) { if (nums.length <= 1 ){ return nums; } int left = -1 ; int right = nums.length; boolean leftisji = true ; boolean rightisou = true ; while (left<right && right >0 && left <nums.length-1 ){ if (rightisou){ right--; rightisou = (nums[right] %2 ==0 ); continue ; } if (leftisji){ left++; leftisji = (nums[left] %2 ==1 ); continue ; } int temp = nums[right]; nums[right] = nums[left]; nums[left] = temp; rightisou = true ; leftisji = true ; } return nums; } }
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Offer22 { public ListNode getKthFromEnd (ListNode head, int k) { ListNode dummy = head; while (k > 0 ){ dummy = dummy.next; k --; } while (dummy != null ){ head = head.next; dummy = dummy.next; } return head; } }
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Offer24 { public static void main (String[] args) { ListNode head = new ListNode (1 ); head.next = new ListNode (2 ); head.next.next = new ListNode (3 ); } public ListNode reverseList (ListNode head) { ListNode prev = null ; ListNode curr = head; while (curr != null ){ ListNode next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; } }
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class Offer25 { public ListNode mergeTwoLists (ListNode l1, ListNode l2) { if (l1 == null ){return l2;} if (l2 == null ){return l1;} ListNode head = null ; if (l1.val < l2.val){ head = new ListNode (l1.val); l1 = l1.next; }else { head = new ListNode (l2.val); l2 = l2.next; } ListNode ans = head; while (true ){ if (l1 == null ){ head.next = l2; break ; } if (l2 == null ){ head.next = l1; break ; } if (l1.val < l2.val){ head.next = l1; l1 = l1.next; head = head.next; }else { head.next = l2; l2 = l2.next; head = head.next; } } return ans; } }
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public class Offer26 { public static void main (String[] args) { TreeNode A = new TreeNode (3 ); A.left = new TreeNode (4 ); A.right = new TreeNode (5 ); A.left.left = new TreeNode (1 ); A.left.right = new TreeNode (2 ); TreeNode B = new TreeNode (4 ); B.left = new TreeNode (1 ); System.out.println(isSubStructure(A, B)); } public static boolean isSubStructure (TreeNode A, TreeNode B) { if (B == null || A == null ){ return false ; } List<TreeNode> pre = preorderTraversal(A); for (TreeNode x:pre){ if (judge(x,B)){ return true ; } } return false ; } public static List<TreeNode> preorderTraversal (TreeNode A) { List<TreeNode> ans = new ArrayList <>(); ans.add(A); if (A.left != null ){ ans.addAll(preorderTraversal(A.left)); } if (A.right != null ){ ans.addAll(preorderTraversal(A.right)); } return ans; } public static boolean judge (TreeNode A,TreeNode B) { if (B == null ){ return true ; } if (A == null ){ return false ; } if (A.val == B.val){ return (judge(A.left,B.left)&&judge(A.right,B.right)); }else { return false ; } } public boolean isSubStructure2 (TreeNode A, TreeNode B) { return (A != null && B != null ) && (recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B)); } boolean recur (TreeNode A, TreeNode B) { if (B == null ) return true ; if (A == null || A.val != B.val) return false ; return recur(A.left, B.left) && recur(A.right, B.right); } }
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Offer27 { public TreeNode mirrorTree (TreeNode root) { if (root ==null ) return null ; TreeNode mirror = new TreeNode (root.val); mirror.left = mirrorTree(root.right); mirror.right = mirrorTree(root.left); return mirror; } }
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Offer28 { public boolean isSymmetric (TreeNode root) { return check(root,root); } public static boolean check (TreeNode a,TreeNode b) { if (a == null && b == null ){ return true ; } if (a == null || b == null ){ return false ; } return a.val == b.val && check(a.left,b.right) &&check(a.right,b.left); } }
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 public class Offer29 { public int [] spiralOrder(int [][] matrix) { int i = 0 ; int j = 0 ; if (matrix.length == 0 )return new int []{}; int index = matrix.length*matrix[0 ].length; int totalLength = matrix.length*matrix[0 ].length; boolean upflag = false ; boolean downflag = false ; boolean leftflag = false ; boolean rightflag = true ; int rightend = matrix[0 ].length-1 ; int leftstart = 0 ; int downend = matrix.length-1 ; int upstart = 0 ; int [] ans = new int [totalLength]; while (index > 0 ){ ans[totalLength-index] = matrix[i][j]; index -= 1 ; if (rightflag && j<rightend){j += 1 ;} else if (leftflag && j>leftstart){j -= 1 ;} else if (downflag && i<downend){i += 1 ;} else if (upflag && i > upstart){i -= 1 ;} else if ( rightflag && j == rightend){ rightflag = false ; downflag = true ; i += 1 ; upstart += 1 ;} else if ( leftflag && j==leftstart){ leftflag = false ; upflag = true ; i -= 1 ; downend -= 1 ;} else if (downflag && i==downend) { downflag = false ; leftflag = true ; j -= 1 ; rightend -= 1 ;} else if (upflag && i == upstart){ upflag = false ; rightflag = true ; j += 1 ; leftstart += 1 ;} } return ans; } }