1.二维数组中的查找
题目描述:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
误区:以斜对角的数组为比较对象,并不是大于array[i][i],小于array[i+1][i+1]的数字还很多很多;满足这个条件只能排除左上角的一小块。

1 //思路:矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,因此从左下角开始查找,当要查找数字比左下角数字大时。右移要查找数字比左下角数字小时,上移。 2 class Solution { 3 public: 4 bool Find(vector<vector<int> > array,int target) { 5 int rowCount = array.size(); 6 int colCount = array[0].size(); 7 int i,j; 8 for(i=rowCount-1,j=0;i>=0&&j<colCount;){ 9 if(target == array[i][j]) 10 return true; 11 if(target < array[i][j]){ 12 i--; 13 continue; 14 } 15 if(target > array[i][j]){ 16 j++; 17 continue; 18 } 19 } 20 return false; 21 } 22 };
2.替换空格
题目描述:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
误区:用循环时,注意到每替换一个空格,字符串的长度都会增加。所以循环必定不能遍历新的字符串。

1 public class Solution { 2 public String replaceSpace(StringBuffer str) { 3 int l=str.length(); 4 for(int i=0;i<l;i++){ 5 if(str.charAt(i)==' ') 6 str.replace(i, i+1, "%20"); 7 } 8 return str.toString(); 9 } 10 }

1 //新建一个字符串,在后面叠加。但是这个方法并不是在原有数组上进行改动。 2 public class Solution { 3 public String replaceSpace(StringBuffer str) { 4 int l=str.length(); 5 String ans=""; 6 for(int i=0;i<l;i++){ 7 if(str.charAt(i)==' ') 8 ans+="%20"; 9 else 10 ans+=str.charAt(i); 11 } 12 return ans; 13 } 14 } 15 16 //这个就比较投机了 17 public class Solution { 18 public static String replaceSpace(StringBuffer str) { 19 String str1=str.toString(); 20 String str2=str1.replace(" ","%20"); 21 return str2; 22 23 } 24 }
3.从尾到头打印链表
题目描述:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList
误区:当java中new了一个对象之后,这个实例就不等于null了,就已经分配内存了;返回的时候不要返回null,会报空指针异常,要用return new ArrayList<>();

1 //这段代码超时了 2 public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { 3 ArrayList<Integer> ans=new ArrayList<>(); 4 if(listNode==null) 5 return new ArrayList<>(); 6 else if(listNode.next==null){ 7 ans.add(listNode.val); 8 return ans; 9 } 10 ListNode head=listNode; 11 ListNode temphead=listNode; 12 ListNode first=null,second=null; 13 while(listNode.next!=null){ 14 first=listNode; 15 second=listNode.next; 16 listNode=listNode.next; 17 } 18 while(true){ 19 ans.add(second.val); 20 ans.add(first.val); 21 if(first==head) 22 break; 23 second=first; 24 while(temphead.next!=null){ 25 if(temphead.next==first) 26 first=temphead; 27 } 28 temphead=listNode; 29 } 30 return ans; 31 } 32 33 //这段用了一个数据结构:栈,很简单 34 public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { 35 ArrayList<Integer> ans=new ArrayList<>(); 36 if(listNode==null) 37 return new ArrayList<>(); 38 39 Stack<Integer> temp=new Stack<>(); 40 while(listNode!=null){ 41 temp.push(listNode.val); 42 listNode=listNode.next; 43 } 44 while(!temp.empty()){ 45 ans.add(temp.pop()); 46 } 47 return ans; 48 } 49 50 //这段用了两个arraylist,一个前向一个逆向 51 public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { 52 ArrayList<Integer> list = new ArrayList<Integer>(); 53 ArrayList<Integer> result = new ArrayList<Integer>(); 54 ListNode temp = listNode; 55 while ( temp != null ) { 56 list.add( temp.val ); 57 temp = temp.next; 58 } 59 for ( int i = list.size()-1; i>=0; i-- ) { 60 result.add( list.get(i) ); 61 } 62 return result; 63 }
4.重建二叉树(中等题)
题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
注意点:递归传入的参数要仔细斟酌

1 public TreeNode reConstructBinaryTree(int [] pre,int [] in) { 2 if(pre==null || in==null || pre.length!=in.length) 3 return null; 4 return help(pre,in,0,pre.length-1,0,in.length-1); 5 } 6 public TreeNode help(int [] pre,int [] in,int startpre,int endpre,int startin,int endin){ 7 if(startin>endin || startpre>endpre) 8 return null; 9 int root=pre[startpre]; 10 int i=0; 11 for(i=startin;i<=endin;i++){ 12 if(in[i]==root) 13 break; 14 } 15 TreeNode ans=new TreeNode(root); 16 ans.left=help(pre,in,startpre+1,startpre+i-startin,startin,i-1); 17 ans.right=help(pre,in,startpre+i-startin+1,endpre,i+1,endin); 18 return ans; 19 }
5.反转链表
题目描述:输入一个链表,反转链表后,输出新链表的表头。
误区:是在原链表的基础上反转,尽量不要借助外部存储结构

/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Solution { public ListNode ReverseList(ListNode head) { ListNode cur=head; ListNode pre=null; ListNode next=null; while(cur!=null){ next=cur.next; cur.next=pre; pre=cur; cur=next; } return pre; } }
6.合并两个排序的链表
题目描述:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
误区:用递归会比较简单;链表题要注意空指针异常和最后要返回头指针

//递归 链接:https://www.nowcoder.com/questionTerminal/d8b6b4358f774294a89de2a6ac4d9337 来源:牛客网 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; } } //非递归 public ListNode Merge(ListNode list1,ListNode list2) { ListNode temp1=list1; ListNode temp2=list2; while(temp2 != null){ //System.out.println(temp1.val); //System.out.println(); if (temp2.val >= temp1.val && temp1.next != null && temp2.val <= temp1.next.val ) { ListNode node = new ListNode(temp2.val); node.next = temp1.next; temp1.next = node; temp1 = temp1.next; temp2 = temp2.next; } else if (temp2.val < temp1.val) { ListNode node = new ListNode(temp2.val); node.next = temp1; temp1 = node; temp2 = temp2.next; } else if (temp2.val >= temp1.val && temp1.next==null) { ListNode node = new ListNode(temp2.val); temp1.next = node; temp1=temp1.next; temp2 = temp2.next; } else temp1 = temp1.next; } return list1; }
7.链表中倒数第k个结点
题目描述:输入一个链表,输出该链表中倒数第k个结点。
误区:在java中,判断一个数据结构是否为空,需要与null比较,!=或者==

1 public class Solution {//复杂度为2n-k 2 public ListNode FindKthToTail(ListNode head,int k) { 3 if(!head) 4 return null; 5 int n=0; 6 ListNode listnode=new ListNode(0); 7 listnode=head; 8 while(listnode){ 9 listnode=listnode.next; 10 n++; 11 } 12 if(k>n) 13 return null; 14 for(int i=0;i<n-k;i++){ 15 head=head.next; 16 } 17 return head; 18 } 19 } 20 21 22 public class Solution {//复杂度为n 23 public ListNode FindKthToTail(ListNode head,int k) { 24 if(head==null||k<=0){ 25 return null; 26 } 27 ListNode pre=head; 28 ListNode last=head; 29 for(int i=1;i<k;i++){ 30 if(pre.next!=null){ 31 pre=pre.next; 32 }else{ 33 return null; 34 } 35 } 36 while(pre.next!=null){ 37 pre = pre.next; 38 last=last.next; 39 } 40 return last; 41 } 42 }
8.树的子结构
题目描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
误区:子结构的题,要想着从大的树每个结点出发,然后遍历小的树,看看能不能遍历完全

1 public class Solution { 2 public boolean HasSubtree(TreeNode root1,TreeNode root2){ 3 if(root1==null || root2==null) 4 return false; 5 else 6 return help(root1,root2) || help(root1.left,root2) || help(root1.right,root2); 7 } 8 9 public boolean help(TreeNode root1,TreeNode root2){ 10 if(root2==null) 11 return true; 12 if(root1==null) 13 return false; 14 if(root1.val==root2.val) 15 return help(root1.left,root2.left) && help(root1.right,root2.right); 16 else 17 return false; 18 } 19 }
9.顺时针打印矩阵(中等题)
题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
误区:边界条件很重要,看这篇博客https://blog.csdn.net/weixin_37672169/article/details/80207479

import java.util.ArrayList; public class Solution { public ArrayList<Integer> printMatrix(int [][] matrix) { ArrayList<Integer> list = new ArrayList<Integer>(); int rows = matrix.length; int cols = matrix[0].length; if(matrix == null || cols <= 0 || rows <= 0){ return null; } int start = 0; while(cols > start*2 && rows > start*2){ printMatrixInCircle(list, matrix, cols, rows, start); ++start; } return list; } private void printMatrixInCircle(ArrayList<Integer> list, int[][] nums, int cols, int rows, int start) { int endX = cols - 1 - start; int endY = rows - 1 - start; //从左到右打印一行 for (int i = start; i <= endX; ++i) { int number = nums[start][i]; list.add(number); } //从上到下打印一列 if(start < endY){ for (int i = start + 1; i <= endY; ++i) { int number = nums[i][endX]; list.add(number); } } //从右向左打印一行 if(start < endX && start < endY){ for (int i = endX-1; i >= start; --i) { int number = nums[endY][i]; list.add(number); } } //从下向上打印一列 if(start < endX && start < endY - 1){ for (int i = endY-1; i >= start + 1; --i) { int number = nums[i][start]; list.add(number); } } } }
10.栈的压入、弹出序列
题目描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
误区:要模拟栈

import java.util.Stack; public class Solution { public boolean IsPopOrder(int [] pushA,int [] popA) { if(pushA.length==0) return false; Stack<Integer> stack=new Stack<Integer> (); for(int i=0,j=0;i<pushA.length;i++){ stack.push(pushA[i]); while(j < pushA.length && stack.peek() == popA[j]){ stack.pop(); j++; } } return stack.empty(); } }
11.二叉搜索树的后序遍历序列
题目描述:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
误区:当有多个情况需要考虑的时候,并行可以转化成串行

public class Solution { public boolean VerifySquenceOfBST(int [] sequence) { int len=sequence.length; if(len==0) return false; return help(sequence,0,len-1); } boolean help(int [] sequence,int start,int end){ if(start>=end) return true; int i=end; while(i > start && sequence[i-1] > sequence[end]) i--; for(int j=i-1;j>=start;j--){ if(sequence[j]>sequence[end]) return false; } return help(sequence,start,i-1) && help(sequence,i,end-1); } }
12.机器人的运动范围
题目描述:地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?。
误区:要注意优化,不然会超时。第二部分是学长的并查集解法,暂时没看懂。

public class Solution { int ans=0; public int movingCount(int threshold, int rows, int cols){ int [][]nums=new int[rows+5][cols+5]; help(0,0,threshold,rows, cols,nums); return ans; } private void help(int i,int j,int threshold,int rows, int cols,int [][]nums){ if(i>rows-1 || j>cols-1 || !check(i,j,threshold)) return; if(nums[i][j]==0){ ans++; nums[i][j]=1; help(i+1,j, threshold, rows, cols, nums); help(i,j+1, threshold, rows, cols, nums); } } private boolean check(int i,int j,int threshold){ int ans=0; while(i>0){ ans+=i%10; i=(i-(i%10))/10; } while(j>0){ ans+=j%10; j=(j-(j%10))/10; } //System.out.println(ans); return ans<=threshold; } public static void main(String [] args){ Solution s=new Solution(); System.out.println(s.movingCount(5,10,10)); } } public class Solution2 { public int movingCount(int threshold, int rows, int cols) { if (threshold < 0) return 0; int[] board = new int[rows * cols]; setBoard(board, cols, threshold); UnionFind uf = new UnionFind(rows * cols); for (int i = 0; i < rows * cols; i++) { int row = i / cols; int col = i % cols; if (board[i] == 1) { if (col + 1 < cols && board[row * cols + col + 1] == 1) uf.union(i, row * cols + col + 1); if (row + 1 < rows && board[(row + 1) * cols + col] == 1) uf.union(i, (row + 1) * cols + col); } } return uf.getCount(); } private void setBoard(int[] board, int cols, int threshold) { for (int i = 0; i < board.length; i++) { int row = i / cols; int col = i % cols; if (getSum(row) + getSum(col) <= threshold) { board[i] = 1; } } } private int getSum(int i) { int sum = 0; while (i != 0) { sum += i % 10; i = i / 10; } return sum; } class UnionFind { private int count = 1; private int[] parent; UnionFind(int n) { parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } } int getCount() { return count; } int find(int i) { if (parent[i] != i) { parent[i] = find(parent[i]); } return parent[i]; } void union(int i, int j) { int pi = find(i); int pj = find(j); if (pi == pj) return; int pos = find(0); if (pi == pos || pj == pos) { parent[pi] = pj; count++; } } } }
13.复杂链表的复制(中等题)
题目描述:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。
误区:这道题的解决方法是散步,1.将每个结点的数值进行复制,赋给新的结点,把新的结点插在相应的结点后面;2.依次复制每个结点的随机指针;3.分离。要注意的是,原链表的结构不能改变,不然通不过,所以最后还有一个还原的操作

1 public class Solution { 2 public RandomListNode Clone(RandomListNode pHead) { 3 if(pHead==null) 4 return null; 5 6 RandomListNode head=pHead; 7 while(head!=null){ 8 RandomListNode temp=new RandomListNode(head.label); 9 temp.next=head.next; 10 head.next=temp; 11 head=head.next.next; 12 } 13 14 RandomListNode head2=pHead; 15 while(head2!=null){ 16 head2.next.random=head2.random==null?null:head2.random.next; 17 head2=head2.next.next; 18 } 19 20 RandomListNode head3=pHead.next; 21 RandomListNode newhead=pHead.next; 22 RandomListNode head4=pHead; 23 while(head3.next!=null){ 24 RandomListNode temp=head3.next; 25 head3.next=head3.next.next; 26 head4.next=temp; 27 head3=head3.next; 28 head4=head4.next; 29 } 30 head4.next=null; 31 return newhead; 32 33 } 34 }
14.二叉搜索树与双向链表
题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
误区:

1 /** 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 15 16 public class Solution { 17 TreeNode head = null; 18 TreeNode realHead = null; 19 public TreeNode Convert(TreeNode pRootOfTree) { 20 ConvertSub(pRootOfTree); 21 return realHead; 22 } 23 24 private void ConvertSub(TreeNode pRootOfTree) { 25 if(pRootOfTree==null) return; 26 ConvertSub(pRootOfTree.left); 27 if (head == null) { 28 head = pRootOfTree; 29 realHead = pRootOfTree; 30 } else { 31 head.right = pRootOfTree; 32 pRootOfTree.left = head; 33 head = pRootOfTree; 34 } 35 ConvertSub(pRootOfTree.right); 36 } 37 }
15.数组中出现次数超过一半的数字
题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
误区:这道题如果用hash就很简单,难的是怎么找空间复杂度为常数的方法,这里推荐“阵地攻守的思想”:第一个数字作为第一个士兵,守阵地;count = 1;遇到相同元素,count++;遇到不相同元素,即为敌人,同归于尽,count--;当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素。再加一次循环,记录这个士兵的个数看是否大于数组一般即可。

1 package hash; 2 3 import java.util.HashMap; 4 //数组中出现次数超过一半的数字 5 6 //别人的思路:采用阵地攻守的思想: 7 //第一个数字作为第一个士兵,守阵地;count = 1; 8 //遇到相同元素,count++; 9 //遇到不相同元素,即为敌人,同归于尽,count--;当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素。 10 //再加一次循环,记录这个士兵的个数看是否大于数组一般即可。 11 public class Solution2 { 12 public int MoreThanHalfNum_Solution(int [] array) { 13 int len=array.length; 14 HashMap<Integer,Integer> hash=new HashMap<>(); 15 for(int i=0;i<len;i++){ 16 17 if(hash.get(array[i])==null) 18 hash.put(array[i],1); 19 else{ 20 21 hash.put(array[i],hash.get(array[i])+1); 22 } 23 if(hash.get(array[i])>len/2) 24 return array[i]; 25 } 26 return 0; 27 } 28 29 public int MoreThanHalfNum_Solution2(int [] array) { 30 int flag=array[0]; 31 int count=1; 32 int nums=0; 33 for(int i=1;i<array.length;i++){ 34 if(array[i]==flag) 35 count++; 36 else 37 count--; 38 if(count==0) { 39 flag = array[i]; 40 count++; 41 } 42 } 43 for(int i=0;i<array.length;i++){ 44 if(array[i]==flag) 45 nums++; 46 } 47 if(nums>array.length/2) 48 return flag; 49 return 0; 50 51 } 52 53 }
16.最小的k个数
题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
误区:这道题第一个想法是hash,也比较简单,但是空间复杂度不定。网上常用方法是最大堆和分治。

1 package 最大堆; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 import java.util.TreeSet; 6 //最小的K个数 7 public class Solution { 8 public static ArrayList<Integer> getLeastNumbers(int []nums, int k) { 9 ArrayList<Integer> list = new ArrayList<Integer>(); 10 int lens = nums.length; 11 if (nums == null || lens == 0 || k > lens || k <= 0) { 12 return list; 13 } 14 TreeSet<Integer> kSet = new TreeSet<Integer>(); 15 for (int i = 0; i < lens; i++) { 16 if (kSet.size() < k) { 17 kSet.add(nums[i]); 18 } else if (nums[i] < kSet.last()) { 19 kSet.remove(kSet.last()); 20 kSet.add(nums[i]); 21 } 22 } 23 Iterator<Integer> iterator = kSet.iterator(); 24 while (iterator.hasNext()) { 25 list.add(iterator.next()); 26 } 27 return list; 28 } 29 }
17.矩阵中的路径
题目描述:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。。
误区:如何把代码写的简洁美观是很重要的一点

1 package shensou; 2 3 //矩阵中的路径 4 public class Solution { 5 public boolean hasPath(char[] matrix, int rows, int cols, char[] str) { 6 int flag[] = new int[matrix.length]; 7 for (int i = 0; i < rows; i++) { 8 for (int j = 0; j < cols; j++) { 9 if (helper(matrix, rows, cols, i, j, str, 0, flag)) 10 return true; 11 } 12 } 13 return false; 14 } 15 16 private boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag) { 17 int index = i * cols + j; 18 if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == 1) 19 return false; 20 if(k == str.length - 1) return true; 21 flag[index] = 1; 22 if (helper(matrix, rows, cols, i - 1, j, str, k + 1, flag) 23 || helper(matrix, rows, cols, i + 1, j, str, k + 1, flag) 24 || helper(matrix, rows, cols, i, j - 1, str, k + 1, flag) 25 || helper(matrix, rows, cols, i, j + 1, str, k + 1, flag)) { 26 return true; 27 } 28 flag[index] = 0; 29 return false; 30 } 31 32 boolean ans=false; 33 public boolean hasPath(char[] matrix, int rows, int cols, char[] str){ 34 int len=matrix.length; 35 boolean [] flag=new boolean[len]; 36 if(len==0) 37 return false; 38 for(int i=0;i<len;i++){ 39 help(matrix,i,str,0,rows,cols,flag); 40 System.out.println("yuanxu"); 41 if(ans) 42 return true; 43 } 44 return false; 45 } 46 void help2(char[] matrix, int i, char[] str,int index,int rows,int cols,boolean []flag){ 47 48 if(i>=matrix.length || i<0 || flag[i] || matrix[i]!=str[index]) 49 return; 50 if(matrix[i]==str[index] && index==str.length-1){ 51 ans=true; 52 return; 53 } 54 55 flag[i]=true; 56 System.out.print("i: "); 57 System.out.print(i); 58 System.out.println(matrix[i]); 59 if(i%cols==0) { 60 help(matrix,i+cols,str,index+1,rows,cols,flag); 61 if(ans) 62 return; 63 help(matrix,i-cols,str,index+1,rows,cols,flag); 64 if(ans) 65 return; 66 help(matrix,i+1,str,index+1,rows,cols,flag); 67 if(ans) 68 return; 69 } 70 71 else if(i%cols==cols-1){ 72 help(matrix,i+cols,str,index+1,rows,cols,flag); 73 if(ans) 74 return; 75 help(matrix,i-cols,str,index+1,rows,cols,flag); 76 if(ans) 77 return; 78 help(matrix,i-1,str,index+1,rows,cols,flag); 79 if(ans) 80 return; 81 } 82 83 else{ 84 help(matrix,i+1,str,index+1,rows,cols,flag); 85 if(ans) 86 return; 87 help(matrix,i-1,str,index+1,rows,cols,flag); 88 if(ans) 89 return; 90 help(matrix,i+cols,str,index+1,rows,cols,flag); 91 if(ans) 92 return; 93 help(matrix,i-cols,str,index+1,rows,cols,flag); 94 if(ans) 95 return; 96 } 97 flag[i]=false; 98 99 100 }
18.求1+2+3+...+n
题目描述:求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
误区:想不到

1 public class Solution { 2 public int Sum_Solution(int n) { 3 int ans=n; 4 boolean a=(ans>0) && ((ans+=Sum_Solution(n-1))>0); 5 return ans; 6 7 } 8 }
19.和为S的连续正数序列
题目描述:小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
误区:用滑动窗口的思想,做过了就会做了

1 import java.util.ArrayList; 2 public class Solution { 3 public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) { 4 if(sum<=0) 5 return new ArrayList<>(); 6 ArrayList<ArrayList<Integer>> ans=new ArrayList<>(); 7 8 int low=1,high=2; 9 10 while(high>low){ 11 int num=(low+high)*(high-low+1)/2; 12 if(num==sum){ 13 ArrayList<Integer> temp=new ArrayList<>(); 14 for(int i=low;i<=high;i++) 15 temp.add(i); 16 ans.add(temp); 17 low++; 18 } 19 else if(num<sum) 20 high++; 21 else 22 low++; 23 } 24 return ans; 25 } 26 }
20.和为S的两个数字
题目描述:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
误区:当两个数和相同时,越靠近乘积越大

1 import java.util.ArrayList; 2 3 public class Solution { 4 public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) { 5 int len=array.length; 6 if(len<=1) 7 return new ArrayList<>(); 8 ArrayList<Integer> ans=new ArrayList<>(); 9 int i=0; 10 int j=len-1; 11 while(i<j){ 12 if (array[i] + array[j]<sum) 13 i++; 14 else if(array[i] + array[j]>sum) 15 j--; 16 else{ 17 ans.add(array[i]); 18 ans.add(array[j]); 19 break; 20 21 } 22 } 23 24 25 return ans; 26 27 } 28 }
21.左旋转字符串
题目描述:汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
误区:如果左移的不是字符串而是数组,就要三次反转来做

1 class Solution { 2 public: 3 string LeftRotateString(string str, int n) 4 { 5 int len = str.size(); 6 if(len == 0) return str; 7 n %= len; 8 for(int i = 0, j = n - 1; i < j; ++i, --j) swap(str[i], str[j]); 9 for(int i = n, j = len - 1; i < j; ++i, --j) swap(str[i], str[j]); 10 for(int i = 0, j = len - 1; i < j; ++i, --j) swap(str[i], str[j]); 11 return str; 12 } 13 }; 14 15 public class Solution { 16 public String LeftRotateString(String str,int n) { 17 18 String ans=""; 19 return ans = (str.length()==0) ? "" : str.substring(n%str.length(),str.length()).concat(str.substring(0,n%str.length())); 20 21 } 22 }
22.扑克牌顺子
题目描述:LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
误区:有没有一种方法可以不排序

1 import java.util.Arrays; 2 3 public class Solution { 4 public boolean isContinuous(int [] numbers) { 5 Arrays.sort(numbers); 6 int temp=0; 7 for(int i=0;i<numbers.length-1;i++){ 8 if(numbers[i]!=0){ 9 if(numbers[i+1]==numbers[i]) 10 return false; 11 else 12 temp=temp+numbers[i+1]-numbers[i]; 13 } 14 } 15 return temp+1<=numbers.length; 16 } 17 }
23.数字在排序数组中出现的次数
题目描述:统计一个数字在排序数组中出现的次数。
误区:两次二分,一次找开头,一次找结尾

1 public class Solution { 2 public int GetNumberOfK(int[] array,int k){ 3 if(array==null||array.length==0) 4 return 0; 5 int first=getFirstK(array,k,0,array.length-1); 6 int last=getLastK(array,k,0,array.length-1); 7 if(first==-1 ||last==-1){ 8 return 0; 9 } 10 else{ 11 return last-first+1; 12 } 13 14 } 15 16 public int getFirstK(int[] array,int k,int start,int end){ 17 while(start<=end){ 18 int mid=(start+end)/2; 19 if(k<array[mid]) 20 end=mid-1; 21 else if(k>array[mid]) 22 start=mid+1; 23 else{ 24 if((mid>0&&array[mid-1]!=k)||mid==0) 25 return mid; 26 else{ 27 end=mid-1; 28 } 29 } 30 } 31 return -1; 32 } 33 34 public int getLastK(int[] array,int k ,int start,int end){ 35 while(start<=end){ 36 int mid=(start+end)/2; 37 if(k<array[mid]) 38 end=mid-1; 39 else if(k>array[mid]) 40 start=mid+1; 41 else{ 42 if((mid<array.length-1&&array[mid+1]!=k)||mid==array.length-1) 43 return mid; 44 else{ 45 start=mid+1; 46 } 47 } 48 } 49 return -1; 50 } 51 }
24.平衡二叉树
题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。
误区:递归,代码要写的好看。从最底下开始

1 //重复计算的代码 2 public classSolution { 3 public boolean IsBalanced_Solution(TreeNode root) { 4 if(root == null) { 5 return true; 6 } 7 return Math.abs(maxDepth(root.left) - maxDepth(root.right)) <= 1 && 8 IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right); 9 } 10 11 private int maxDepth(TreeNode root) { 12 if(root == null) { 13 return 0; 14 } 15 return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)); 16 } 17 } 18 19 20 //不重复计算的代码 21 public class Solution { 22 public boolean IsBalanced_Solution(TreeNode root) { 23 return getDepth(root) != -1; 24 } 25 26 private int getDepth(TreeNode root) { 27 if (root == null) return 0; 28 int left = getDepth(root.left); 29 if (left == -1) return -1; 30 int right = getDepth(root.right); 31 if (right == -1) return -1; 32 return Math.abs(left - right) > 1 ? -1 : 1 + Math.max(left, right); 33 } 34 }
25.数组中只出现一次的数字
题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
误区:第一档是遍历,第二档是hash,第三档是位运算

1 import java.util.Arrays; 2 import java.util.HashMap; 3 import java.util.HashSet; 4 import java.util.Set; 5 6 public class Solution { 7 public void FindNumsAppearOnce2(int [] array,int num1[] , int num2[]) { 8 if(array.length>1){ 9 Arrays.sort(array); 10 int i=1; 11 int flag=0; 12 while(i<array.length){ 13 if(array[i]==array[i-1]){ 14 if(i+2>=array.length){ 15 num2[0]=array[i+1]; 16 break; 17 } 18 else 19 i+=2; 20 } 21 22 else{ 23 if(flag==0){ 24 if(i==array.length-1){ 25 num1[0]=array[i-1]; 26 num2[0]=array[i]; 27 break; 28 } 29 num1[0]=array[i-1]; 30 flag++; 31 } 32 else{ 33 num2[0]=array[i-1]; 34 break; 35 } 36 i++; 37 } 38 39 } 40 } 41 42 } 43 44 public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { 45 Set<Integer> hm=new HashSet<>(); 46 for(int i=0;i<array.length;i++){ 47 if(hm.contains(array[i])) 48 hm.remove(array[i]); 49 else 50 hm.add(array[i]); 51 } 52 int []temp={0,0}; 53 int j=0; 54 for(int i :hm){ 55 temp[j]=i; 56 j++; 57 } 58 num1[0]=temp[0]; 59 num2[0]=temp[1]; 60 61 } 62 }
26.把数组排成最小的数
题目描述:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
误区:自定义比较器很奇妙

1 package 数组; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.Comparator; 6 7 public class Solution { 8 public String PrintMinNumber(int [] numbers) { 9 int n; 10 String s=""; 11 ArrayList<Integer> list= new ArrayList<Integer>(); 12 n=numbers.length; 13 for(int i=0;i<n;i++){ 14 list.add(numbers[i]); 15 16 } 17 list.sort(new Comparator<Integer>() { 18 19 public int compare(Integer str1, Integer str2) { 20 String s1 = str1 + "" + str2; 21 String s2 = str2 + "" + str1; 22 return s1.compareTo(s2); 23 } 24 }); 25 26 for(int j:list){ 27 s+=j; 28 } 29 return s; 30 31 } 32 }
27.把字符串转换成整数
题目描述:将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。
误区:溢出判断

1 public class Solution { 2 public int StrToInt(String str) { 3 if(str.length()==0) 4 return 0; 5 int ans=0; 6 int flag=0; 7 if(str.charAt(0)=='-') 8 flag=-1; 9 else 10 flag=1; 11 12 for(int i=0;i<str.length();i++){ 13 if(i==0 && ((str.charAt(i)=='+' || str.charAt(i)=='-'))) 14 continue; 15 else if(str.charAt(i)>='0' && str.charAt(i)<='9'){ 16 int temp=ans; 17 ans=ans*10+(str.charAt(i)-'0'); 18 if((temp-(str.charAt(i)-'0')/10!=ans))//溢出判断 19 return 0; 20 21 } 22 23 else 24 return 0; 25 } 26 return ans*flag; 27 28 } 29 30 public static void main(String[] args) { 31 Solution s=new Solution(); 32 int a=s.StrToInt("2147483648"); 33 System.out.println(a); 34 } 35 }
8.反转链表
题目描述:输入一个链表,反转链表后,输出新链表的表头。
误区:是在原链表的基础上反转,尽量不要借助外部存储结构