3~13
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
通过交换使得每一个数字回到与他自己的位置(最多两次),然后判断是否与相应下标的数字相同即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public static void swap (int []arr,int i,int j) { int temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } public int findRepeatNumber (int [] nums) { for (int i=0 ;i<nums.length;i++){ while (nums[i]!=i){ if (nums[i]==nums[nums[i]]) { return nums[i]; } swap(nums,i,nums[i]); } } return -1 ; } }
或者是直接通过Set或者Map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public int findRepeatNumber (int [] nums) { Set<Integer> set=new HashSet <>(); for (int a:nums) { if (!set.add(a)) return a; } return -1 ; } } class Solution { public int findRepeatNumber (int [] nums) { Map<Integer, Boolean> map=new HashMap <>(); for (int num : nums) { if (map.containsKey(num)) return num; else map.put(num, true ); } return -1 ; } }
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
每一次都从右上角开始查询,
如果是大于target字的数,那么这个数字所在列的所有数字也一定大于target, 剔除该行
如果是小于target字的数,那么这个数字所在的行所有数字也一定小于target,剔除该列
这样每一步缩小范围,直到查找范围为null或者找到target
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 class Solution {public static boolean findNumberIn2DArray (int [][] matrix, int target) { boolean isFound=false ; if (matrix == null || matrix.length == 0 || matrix[0 ].length == 0 ) { return isFound; } int rows = matrix.length; int columns=matrix[0 ].length; if (matrix!=null &&rows>0 &&columns>0 ){ int row=0 ,column=columns-1 ; while (row<rows&&column>=0 ) { if (matrix[row][column]==target) { isFound=true ; break ; }else if (matrix[row][column]>target) { column--; }else { row++; } } } return isFound; } }
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
本题如果使用cpp 来写的话, 核心思想就是 从末尾开始赋值, 可以节省大量的时间(通过这样做就不需要string 因为前面的数组插入数据 而后移 导致消耗时间)
由于java String 的不可变性, 本体java代码直接使用 StringBuffer一个个的append 即可
image-20220717181023757
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution { public String replaceSpace (String s) { StringBuffer res=new StringBuffer ("" ); for (int i = 0 ; i < s.length(); i++){ if (s.charAt(i)==' ' ){ res.append("%20" ); }else { res.append(s.charAt(i)); } } return res.toString(); } }
或者直接
return s.replaceAll(" ","%20");一行代码搞定。
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
通过ArrayList 添加 每个节点的val ,然后反向赋值给 int []res ,最后返回res 即可
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 { public int [] reversePrint(ListNode head) { if (head==null ) return new int [0 ]; ArrayList<Integer> list=new ArrayList <>(); while (head.next!=null ){ list.add(head.val); head=head.next; } list.add(head.val); int len = list.size(); int []res=new int [len]; for (int i = len-1 ; i >=0 ; i--) { res[i]=list.get(len-i-1 ); } return res; } }
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
image-20220719143417614
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 TreeNode buildTree (int [] preorder, int [] inorder) { return f(preorder,inorder,null ); } int preindex; int inindex; public TreeNode f (int []preorder,int []inorder,TreeNode finish) { if (preindex==preorder.length||(finish!=null &&inorder[inindex]==finish.val)) return null ; TreeNode root=new TreeNode (preorder[this .preindex++]); root.left=f(preorder,inorder,root); this .inindex++; root.right=f(preorder,inorder,finish); return root; } }
中序遍历二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution { List<Integer> list=new ArrayList (); public List<Integer> inorderTraversal (TreeNode root) { dfs(root); return list; } public void dfs (TreeNode root) { if (root==null ) return ; dfs(root.left); list.add(root.val); dfs(root.right); } }
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
Stack 类
栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。
序号
方法描述
1
boolean empty() 测试堆栈是否为空。
2
Object peek( ) 查看堆栈顶部的对象,但不从堆栈中移除它。
3
Object pop( ) 移除堆栈顶部的对象,并作为此函数的值返回该对象。
4
Object push(Object element) 把项压入堆栈顶部。
5
int search(Object element) 返回对象在堆栈中的位置,以 1 为基数。
使用两个Stack: A , B。 其中A 用来添加 元素, B用来移除元素
A B 的元素的顺序相反
注意appendTail方法返回的 都是null
deleteHead返回的是当前删除的元素
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 CQueue { public CQueue () { A=new Stack <>(); B=new Stack <>(); } Stack<Integer> A; Stack<Integer> B; public void appendTail (int value) { A.add(value); } public int deleteHead () { if (!B.isEmpty()) { return B.pop(); } if (A.isEmpty()) return -1 ; while (!A.isEmpty()) { B.add(A.pop()); } return B.pop(); } }
示例 1:
1 2 3 4 输入: ["CQueue" ,"appendTail" ,"deleteHead" ,"deleteHead" ] [[],[3 ],[],[]] 输出:[null ,null ,3 ,-1 ]
示例2
1 2 3 4 输入: ["CQueue" ,"deleteHead" ,"appendTail" ,"appendTail" ,"deleteHead" ,"deleteHead" ] [[],[],[5 ],[2 ],[],[]] 输出:[null ,-1 ,null ,null ,5 ,2 ]
写一个函数,输入 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。
N 较小, 直接循环计算即可
需要注意的是 (a+b)%mod < = > (a%mod+b%mod)%mod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution { static final int mod=1000000007 ; public int fib (int n) { if (n==0 ) return 0 ; if (n==1 ||n==2 ) return 1 ; long f1=0L ,f2=1L ,f3=1L ; for (int i=1 ;i<n;i++ ) { long temp = f3; f3=(f1%mod+f2%mod)%mod; f1=f2; f2=f3; } return (int )f3%mod; } }
与上一题类似
1、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public int numWays (int n) { return fib(n); } static int mod=1000000007 ; public int fib (int n) { if (n==2 ) return 2 ; if (n==1 ||n==0 ) return 1 ; long f1=1L ,f2=1L ,f3=2L ; for (int i=1 ;i<n;i++ ) { long temp = f3; f3=(f1%mod+f2%mod)%mod; f1=f2; f2=f3; } return (int )f3%mod; } }
2、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution { static int mod=1000000007 ; int []res=new int [101 ]; public int numWays (int n) { res[0 ]=1 ; res[1 ]=1 ; res[2 ]=2 ; for (int i=3 ;i<=100 ;i++) { res[i]=(res[i-1 ]%mod+res[i-2 ]%mod)%mod; if (i==n) break ; } return res[n]; } }
3、 将上一个的数组替换为了HashMap ,可以节省内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { Map<Integer,Integer> res=new HashMap <>(); static int mod=1000000007 ; public int numWays (int n) { res.put(0 ,1 ); res.put(1 ,1 ); res.put(2 ,2 ); for (int i=3 ;i<=n;i++) { res.put(i,(res.get(i-1 )%mod+res.get(i-2 )%mod)%mod); } return res.get(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]] 。
image-20220719174150375
遍历数组,由于原来的数组一定是升序排列, 那么如果出现了 相邻的两个数字,后面的数字小于前面的数字,说明后面的这个数字就是原来的数组的第一项
,如果遍历完没有满足条件的情况,说明旋转后的数组与原来的数组一模一样。
1 2 3 4 5 6 7 8 9 class Solution { public int minArray (int [] numbers) { for (int i = 1 ; i < numbers.length; i++) { if (numbers[i]<numbers[i-1 ]) return numbers[i]; } return numbers[0 ]; } }
通过判断中点 与 右端的大小关系找到 原数组第一个元素所在的区间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public int minArray(int[] numbers) { int l=0,r=numbers.length-1; while(l<r){ int m=(l+r)/2; if(numbers[m]>numbers[r]) l=m+1; else if(numbers[m]<numbers[r]) r=m; else r--; } return numbers[l]; } }
难度中等655
给定一个 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 class Solution { boolean res=false ; int totalLen; String word; public boolean exist (char [][] board, String word) { totalLen=word.length(); this .word=word; dfs(board,new StringBuilder ("" ),0 ,0 ); return res; } public void dfs (char [][]board , StringBuilder s,int i,int j) { if (i<0 ||j<0 ||i>=board.length||j>=board[0 ].length||board[i][j]=='\0' ) return ; s.append(board[i][j]); if (s.length()==totalLen){ if (s.toString().equals(word)) res=true ; return ; } if (res) return ; char temp=board[i][j]; board[i][j]='\0' ; dfs(board,new StringBuilder (s.toString()),i,j-1 ); dfs(board,new StringBuilder (s.toString()),i,j+1 ); dfs(board,new StringBuilder (s.toString()),i+1 ,j); dfs(board,new StringBuilder (s.toString()),i-1 ,j); board[i][j]=temp; } }
i
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 class Solution { boolean res=false ; int totalLen; String word; public boolean exist (char [][] board, String word) { totalLen=word.length(); this .word=word; for (int i = 0 ; i < board.length; i++) { for (int j = 0 ; j < board[0 ].length; j++) { dfs(board,new StringBuilder ("" ),i,j); } } return res; } public void dfs (char [][]board , StringBuilder s,int i,int j) { if (i<0 ||j<0 ||i>=board.length||j>=board[0 ].length||board[i][j]=='\0' ) return ; s.append(board[i][j]); if (s.length()==totalLen){ if (s.toString().equals(word)) res=true ; return ; } if (res) return ; char temp=board[i][j]; board[i][j]='\0' ; dfs(board,new StringBuilder (s.toString()),i+1 ,j); dfs(board,new StringBuilder (s.toString()),i,j-1 ); dfs(board,new StringBuilder (s.toString()),i,j+1 ); dfs(board,new StringBuilder (s.toString()),i-1 ,j); board[i][j]=temp; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public boolean exist (char [][] board, String word) { char [] words = word.toCharArray(); for (int i = 0 ; i < board.length; i++) { for (int j = 0 ; j < board[0 ].length; j++) { if (dfs(board, words, i, j, 0 )) return true ; } } return false ; } public boolean dfs (char [][]board,char []words, int i,int j,int k) { if (i<0 ||j<0 ||i>=board.length||j>=board[0 ].length||words[k]!=board[i][j]) return false ; if (k==words.length-1 ) return true ; board[i][j] = '\0' ; boolean res= dfs(board,words,i,j-1 ,k+1 )||dfs(board,words,i-1 ,j,k+1 ) || dfs(board,words,i,j+1 ,k+1 )||dfs(board,words,i+1 ,j,k+1 ); board[i][j]=words[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。请问该机器人能够到达多少个格子?
image-20220719194018772
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public int movingCount(int m, int n, int k) { int res=0; boolean visited[][]=new boolean[m][n]; return dfs(visited,m,n,k,0,0); } public int dfs(boolean visited[][],int m,int n,int k,int i,int j) { // 终止 ;走到了边界 或者 数位之和不满足条件了 或者当前的格子已经走过了 if(i>=m||j>=n||sum(i)+sum(j)>k||visited[i][j]) return 0; visited[i][j]=true; // 标记,表示当前格子走了 // 当前格子 + 往下走+往右走 return 1+ dfs( visited,m,n,k,i+1,j)+dfs(visited, m, n, k,i, j+1); } public static int sum(int n){ // 获取一个数字的 每个位数之和 (由于题目要求的n<=100,因此直接return 即可) return n==100?1:n%10+n/10; } }
另一道相似的题目
给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
岛屿的面积是岛上值为 1 的单元格的数目。
计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
image-20220719202608622
这个题跟上一个不太一样,这个是四周发散的
先遍历, 如果位置的值是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 public class Solution { public int maxAreaOfIsland (int [][] grid) { int max_res=0 ; int m=grid.length, n=grid[0 ].length; for (int i = 0 ; i < m; i++) { for (int j = 0 ; j < n; j++) { if (grid[i][j]==1 ) max_res= Math.max(DFS(grid, m, n, i, j), max_res); } } return max_res; } public int DFS (int [][]grid,int m,int n,int i,int j) { if (i<0 ||j<0 ||i>= m||j>=n||grid[i][j]==0 ) return 0 ; if (grid[i][j]==1 ){ grid[i][j]=0 ; return 1 + DFS(grid,m, n, i+1 , j)+ DFS(grid,m, n, i, j+1 )+ DFS(grid,m, n, i, j-1 )+ DFS(grid,m, n, i-1 , j); } return 0 ; } }