數組
1 數組中重複的數字
主要思想是讓每個數字回到自己對應的索引位置,如果已經存在就代表重複了。
public int findRepeatNumber(int[] nums) {
for(int i=0;i<nums.length;i++){
//獲取當前位置的數字
int nowNumber=nums[i];
//如果當前數字和目前索引不等
if(nowNumber!=i){
//如果當前數字對應位置已經存放了當前數字,代表重複
if(nowNumber==nums[nowNumber])
return nowNumber;
else{
//置換
nums[i]=nums[nowNumber];
nums[nowNumber]=nowNumber;
}
}
}
return 0;
}
2 二維數組中的查找
從二維數組的右上角開始查找,比目標值小就下移,大就左移。
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix.length==0||matrix[0].length==0)
return false;
//行條件
int Row=matrix.length;
//初始行和列
int row=0;
int col=matrix[0].length-1;
int nowNumber=matrix[row][col];
while(row<Row&&col>=0){
if(matrix[row][col]==target)
return true;
else if(matrix[row][col]<target)
row++;
else
col--;
}
return false;
}
3 和爲s的兩個數字
雙指針
public int[] twoSum(int[] nums, int target) {
int i=0;
int j=nums.length-1;
int sum=0;
while(i<j){
sum=nums[i]+nums[j];
if(sum>target)
j--;
else if(sum<target)
i++;
else
return new int[]{nums[i],nums[j]};
}
return new int[2];
}
4 旋轉數組的最小數字
找到第一個比前一個元素小的數字,沒找到就返回第一個
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];
}
5 打印從1到最大的n位數
public int[] printNumbers(int n) {
int number=0;
while(n!=0){
number=number*10+9;
n--;
}
int[] arr=new int[number];
for(int i=0;i<number;i++)
arr[i]=i+1;
return arr;
}
6 調整數組順序
public int[] exchange(int[] nums) {
int l=0;
int r=nums.length-1;
while(l<r){
while(l<=r&&nums[l]%2!=0)
l++;
while(l<=r&&nums[r]%2==0)
r--;
if(l<r){
int temp=nums[l];
nums[l]=nums[r];
nums[r]=temp;
}
}
return nums;
}
7 順時針打印矩陣
public int[] spiralOrder(int[][] matrix) {
if(matrix.length==0||matrix[0].length==0)
return new int[0];
int m=matrix.length;
int n=matrix[0].length;
int[] arr=new int[m*n];
int index=0;
int top=0,bottom=m-1;
int left=0,right=n-1;
while(true){
//左向右
for(int i=left;i<=right;i++)
arr[index++]=matrix[top][i];
if(++top>bottom) break;
//上向下
for(int i=top;i<=bottom;i++)
arr[index++]=matrix[i][right];
if(--right<left) break;
//右向左
for(int i=right;i>=left;i--)
arr[index++]=matrix[bottom][i];
if(--bottom<top) break;
//下向上
for(int i=bottom;i>=top;i--)
arr[index++]=matrix[i][left];
if(++left>right) break;
}
return arr;
}
8 數組中超過一次的數字
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
9 最小的k個數
public int[] getLeastNumbers(int[] arr, int k) {
Arrays.sort(arr);
return Arrays.copyOf(arr,k);
}
10 連續子數組最大和
public int maxSubArray(int[] nums) {
if(nums.length==0)
return 0;
int maxSum=nums[0];
int tempSum=nums[0];
for(int i=1;i<nums.length;i++){
if(tempSum<0)
tempSum=nums[i];
else
tempSum+=nums[i];
maxSum=Math.max(maxSum,tempSum);
}
return maxSum;
}
11 禮物的最大價值
public int maxValue(int[][] grid) {
int row=grid.length;
int col=grid[0].length;
//第一列
for(int i=1;i<row;i++){
grid[i][0]+=grid[i-1][0];
}
//第一行
for(int i=1;i<col;i++){
grid[0][i]+=grid[0][i-1];
}
//動態規劃
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){
grid[i][j]+=Math.max(grid[i-1][j],grid[i][j-1]);
}
}
return grid[row-1][col-1];
}
12 把數組排成最小的數
public String minNumber(int[] nums) {
String[] strs=new String[nums.length];
for(int i=0;i<nums.length;i++)
strs[i]= String.valueOf(nums[i]);
Arrays.sort(strs,(x,y)->(x+y).compareTo(y+x));
StringBuilder sb = new StringBuilder();
for(String str:strs)
sb.append(str);
return sb.toString();
}
13 在排序數組查找數字
public int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=left+((right-left)>>1);
if(nums[mid]<target)
left=mid+1;
else if(nums[mid]>target)
right=mid-1;
else{
int cnt=1;
int index=mid-1;
while(index>=0&&nums[index]==target){
cnt++;
index--;
}
index=mid+1;
while(index<nums.length&&nums[index]==target){
cnt++;
index++;
}
return cnt;
}
}
return 0;
}
14 0~n-1缺失的數字
public int missingNumber(int[] nums) {
for(int i=0;i<nums.length;i++){
if(i!=nums[i])
return i;
}
return nums.length;
}
15 和爲s的連續正數序列
public int[][] findContinuousSequence(int target) {
List<int[]> res=new ArrayList<>();
int left=1;
int right=2;
int sum=0;
while(left<right){
sum=(left+right)*(right-left+1)/2;
if(sum>target)
left++;
else if(sum<target)
right++;
else{
int[] arr=new int[right-left+1];
int index=0;
for(int i=left;i<=right;i++){
arr[index++]=i;
}
res.add(arr);
left++;
}
}
return res.toArray(new int[0][]);
}
16 買賣股票
動態規劃
public int maxProfit(int[] prices) {
if(prices.length==0)
return 0;
int maxProfit=0;
int minBuy=prices[0];
for(int i=1;i<prices.length;i++){
int profit=prices[i]-minBuy;
maxProfit=Math.max(maxProfit,profit);
minBuy=Math.min(minBuy,prices[i]);
}
return maxProfit;
}
17 構建乘積數組
public int[] constructArr(int[] a) {
int[] b=new int[a.length];
for(int i=0,n=1;i<a.length;i++){
b[i]=n;
n*=a[i];
}
for(int i=a.length-1,n=1;i>=0;i--){
b[i]*=n;
n*=a[i];
}
return b;
}
18 撲克牌中的順子
public boolean isStraight(int[] nums) {
int joker=0;
Arrays.sort(nums);
for(int i=0;i<4;i++){
if(nums[i]==0)
joker++;
else if(nums[i]==nums[i+1])
return false;
}
return nums[4]-nums[joker]<5;
}
二叉樹
1 樹的子結構
public boolean isSubStructure(TreeNode A, TreeNode B) {
if(A==null||B==null)
return false;
return isSub(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B);
}
public boolean isSub(TreeNode A,TreeNode B){
if(B==null)
return true;
if(A==null||A.val!=B.val)
return false;
return isSub(A.left,B.left)&&isSub(A.right,B.right);
}
2 二叉樹的鏡像
public TreeNode mirrorTree(TreeNode root) {
if(root!=null){
TreeNode left=mirrorTree(root.left);
TreeNode right=mirrorTree(root.right);
root.left=right;
root.right=left;
}
return root;
}
3 判斷對稱二叉樹
public boolean isSymmetric(TreeNode root) {
if(root==null)
return true;
return isSymmetric(root.left,root.right);
}
public boolean isSymmetric(TreeNode n1,TreeNode n2){
if((n1!=null&&n2==null)||(n1==null&&n2!=null))
return false;
if(n1==null&&n2==null)
return true;
if(n1.val!=n2.val)
return false;
else{
return isSymmetric(n1.left,n2.right)&&isSymmetric(n1.right,n2.left);
}
}
4 從上到下打印二叉樹
public int[] levelOrder(TreeNode root) {
List<TreeNode> treeList=new ArrayList<>();
List<Integer> list=new ArrayList<>();
if(root==null)
return new int[0];
treeList.add(root);
while(treeList.size()!=0){
TreeNode temp=treeList.get(0);
list.add(temp.val);
treeList.remove(0);
if(temp.left!=null){
treeList.add(temp.left);
}
if(temp.right!=null){
treeList.add(temp.right);
}
}
//返回結果
int[] res=new int[list.size()];
for(int i=0;i<res.length;i++)
res[i]=list.get(i);
return res;
}
5 從上到下打印二叉樹2
public List<List<Integer>> levelOrder(TreeNode root) {
List<TreeNode> treeList=new ArrayList<>();
List<Integer> temp;
List<List<Integer>> resultList=new ArrayList<>();
if(root!=null){
treeList.add(root);
while(treeList.size()!=0){
int n=treeList.size();
temp=new ArrayList<>();
for(int i=0;i<n;i++){
TreeNode node=treeList.remove(0);
temp.add(node.val);
if(node.left!=null)
treeList.add(node.left);
if(node.right!=null)
treeList.add(node.right);
}
resultList.add(temp);
}
}
return resultList;
}
6 二叉搜索樹第k大結點
中序遍歷
public int kthLargest(TreeNode root, int k) {
List<Integer> list=new ArrayList<>();
inOrder(root,list);
return list.get(list.size()-k);
}
public void inOrder(TreeNode root,List<Integer> list){
if(root!=null){
inOrder(root.left,list);
list.add(root.val);
inOrder(root.right,list);
}
}
7 二叉樹的深度
public int maxDepth(TreeNode root) {
if(root==null)
return 0;
return 1+Math.max(maxDepth(root.left),maxDepth(root.right));
}
8 判斷平衡二叉樹
public boolean isBalanced(TreeNode root) {
if(root==null)
return true;
int hL=maxDepth(root.left);
int hR=maxDepth(root.right);
return !(Math.abs(hL-hR)>1)&&isBalanced(root.left)&&isBalanced(root.right);
}
public int maxDepth(TreeNode root) {
if(root==null)
return 0;
return 1+Math.max(maxDepth(root.left),maxDepth(root.right));
}
9 二叉搜索樹的最近公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root!=null){
if(p.val<root.val&&q.val<root.val)
return lowestCommonAncestor(root.left,p,q);
else if(p.val>root.val&&q.val>root.val)
return lowestCommonAncestor(root.right,p,q);
else
return root;
}
return root;
}
10 二叉樹的最近公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null||root==p||root==q)
return root;
TreeNode left=lowestCommonAncestor(root.left,p,q);
TreeNode right=lowestCommonAncestor(root.right,p,q);
if(left==null)
return right;
if(right==null)
return left;
return root;
}
字符串
1 替換空格
利用StringBuilder
public String replaceSpace(String s) {
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
if(s.charAt(i)==' ')
sb.append("%20");
else
sb.append(s.charAt(i));
}
return sb.toString();
}
2 第一個只出現一次的字符
public char firstUniqChar(String s) {
int[] words=new int[128];
for (int i = 0; i <s.length() ; i++) {
words[s.charAt(i)]++;
}
for (int i = 0; i <s.length() ; i++) {
if(words[s.charAt(i)]==1)
return s.charAt(i);
}
return ' ';
}
3 數字翻譯字符串
動態規劃
public int translateNum(int num) {
String number = String.valueOf(num);
int[] dp=new int[number.length()+1];
dp[0]=1;
dp[1]=1;
for(int i=2;i<dp.length;i++){
String s = number.substring(i - 2, i);
if(s.compareTo("10")>=0&&s.compareTo("25")<=0)
dp[i]=dp[i-1]+dp[i-2];
else
dp[i]=dp[i-1];
}
return dp[dp.length-1];
}
4 左旋字符串
public String reverseLeftWords(String s, int n) {
return s.substring(n)+s.substring(0,n);
}
5 翻轉單詞字符串
public String reverseWords(String s) {
s=s.trim();
int j=s.length()-1;
int i=j;
StringBuilder sb=new StringBuilder();
while(i>=0){
while(i>=0&&s.charAt(i)!=' ')
i--;
sb.append(s.substring(i+1,j+1)+" ");
while(i>=0&&s.charAt(i)==' ')
i--;
j=i;
}
return sb.toString().trim();
}
鏈表
1 從尾到頭打印鏈表
利用棧的LIFO
public int[] reversePrint(ListNode head) {
Stack<Integer> stack=new Stack<>();
while(head!=null){
stack.push(head.val);
head=head.next;
}
int[] res=new int[stack.size()];
for(int i=0;i<res.length;i++){
res[i]=stack.pop();
}
return res;
}
2 刪除鏈表的結點
public ListNode deleteNode(ListNode head, int val) {
ListNode pre=new ListNode(-1);
ListNode res=pre;
pre.next=head;
while(head!=null){
if(head.val==val){
pre.next=head.next;
break;
}
pre=pre.next;
head=head.next;
}
return res.next;
}
3 鏈表中倒數第k個結點
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode pre=new ListNode(-1);
pre.next=head;
ListNode p=pre;
ListNode q=pre;
for(int i=0;i<k;i++){
q=q.next;
}
while(q!=null){
p=p.next;
q=q.next;
}
return p;
}
4 反轉鏈表
public ListNode reverseList(ListNode head) {
ListNode pre=null;
ListNode cur=head;
ListNode next=null;
while(cur!=null){
next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
5 合併鏈表
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode pre=new ListNode(-1);
ListNode res=pre;
while(l1!=null&&l2!=null){
if(l1.val<=l2.val){
pre.next=new ListNode(l1.val);
l1=l1.next;
}else{
pre.next=new ListNode(l2.val);
l2=l2.next;
}
pre=pre.next;
}
while(l1!=null){
pre.next=new ListNode(l1.val);
pre=pre.next;
l1=l1.next;
}
while(l2!=null){
pre.next=new ListNode(l2.val);
pre=pre.next;
l2=l2.next;
}
return res.next;
}
6 兩個鏈表的第一個公共結點
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null&&headB==null)
return null;
ListNode p=headA;
ListNode q=headB;
while(p!=q){
p=p==null?headB:p.next;
q=q==null?headA:q.next;
}
return p;
}
數學
1 整數翻轉
public int reverse(int x) {
int res=0;
while (x!=0){
int pop=x%10;
x/=10;
if(res>Integer.MAX_VALUE/10||(res==Integer.MAX_VALUE/10&&pop>7))
return 0;
if(res<Integer.MIN_VALUE/10||(res==Integer.MIN_VALUE/10&&pop<-8))
return 0;
res=res*10+pop;
}
return res;
}
2 迴文數
public boolean isPalindrome(int x) {
if(x<0||(x%10==0&&x!=0))
return false;
int rev=0;
while (x>rev){
rev=rev*10+x%10;
x/=10;
}
return rev==x||rev/10==x;
}
3 剪繩子
public int cuttingRope(int n) {
if(n<=3)
return n-1;
int a=n/3;
int b=n%3;
if(b==0)
return (int)Math.pow(3,a);
if(b==1)
return (int)Math.pow(3,a-1)*4;
return (int)Math.pow(3,a)*2;
}
4 醜數
public int nthUglyNumber(int n) {
int[] dp=new int[n];
dp[0]=1;
int a=0,b=0,c=0;
for(int i=1;i<n;i++){
int num1=dp[a]*2;
int num2=dp[b]*3;
int num3=dp[c]*5;
int minNum=Math.min(Math.min(num1,num2),num3);
dp[i]=minNum;
if(num1==minNum)
a++;
if(num2==minNum)
b++;
if(num3==minNum)
c++;
}
return dp[n-1];
}
5 約瑟夫環
反推法
public int lastRemaining(int n, int m) {
int res=0;
for(int i=2;i<=n;i++){
res=(res+m)%i;
}
return res;
}
棧和隊列
1 棧實現隊列
class CQueue {
private Stack<Integer> s1;
private Stack<Integer> s2;
public CQueue() {
s1=new Stack<>();
s2=new Stack<>();
}
public void appendTail(int value) {
s1.push(value);
}
public int deleteHead() {
if(!s2.isEmpty())
return s2.pop();
if(!s1.isEmpty()){
while(!s1.isEmpty()){
s2.push(s1.pop());
}
return s2.pop();
}
return -1;
}
}
2 包含min函數的棧
class MinStack {
private Stack<Integer> s1=new Stack<>();
private Stack<Integer> s2=new Stack<>();
/** initialize your data structure here. */
public MinStack() {
}
public void push(int x) {
s1.push(x);
if(s2.isEmpty()||x<=s2.peek())
s2.push(x);
}
public void pop() {
if(s1.peek().equals(s2.peek()))
s2.pop();
s1.pop();
}
public int top() {
return s1.peek();
}
public int min() {
return s2.isEmpty()?0:s2.peek();
}
}
3 棧的壓入和彈出
public boolean validateStackSequences(int[] pushed, int[] popped) {
Stack<Integer> stack=new Stack<>();
int pushIndex=0;
int popIndex=0;
while(pushIndex!=pushed.length){
stack.push(pushed[pushIndex]);
while(!stack.isEmpty()&&stack.peek()==popped[popIndex]){
stack.pop();
popIndex++;
}
pushIndex++;
}
return stack.isEmpty();
}
遞歸和循環
1 斐波那契數列
public int fib(int n) {
if(n==0||n==1)
return n;
int[] arr=new int[n+1];
arr[0]=0;
arr[1]=1;
for(int i=2;i<arr.length;i++)
arr[i]=(arr[i-1]+arr[i-2])%1000000007;
return arr[n];
}
2 青蛙跳臺階問題
public int numWays(int n) {
if(n==0||n==1)
return 1;
int[] arr=new int[n+1];
arr[0]=1;
arr[1]=1;
for(int i=2;i<arr.length;i++)
arr[i]=(arr[i-1]+arr[i-2])%1000000007;
return arr[n];
}
回溯法
1 機器人的運動範圍
public int movingCount(int m, int n, int k) {
boolean[][] visited=new boolean[m][n];
return canReach(0,0,m,n,k,visited);
}
public int canReach(int i,int j,int m,int n,int k,boolean[][] visited){
if(i==m||i<0||j==n||j<0||(i/10+i%10+j/10+j%10>k)||visited[i][j])
return 0;
visited[i][j]=true;
return 1+canReach(i+1,j,m,n,k,visited)+canReach(i,j+1,m,n,k,visited)
+canReach(i-1,j,m,n,k,visited)+canReach(i,j-1,m,n,k,visited);
}
2 字符串的排列
class Solution {
List<String> list=new ArrayList<>();
char[] c;
public String[] permutation(String s) {
c=s.toCharArray();
dfs(0);
return list.toArray(new String[list.size()]);
}
public void dfs(int x){
if(x==c.length-1){
list.add(String.valueOf(c));
return;
}
HashSet<Character> set=new HashSet<>();
for(int i=x;i<c.length;i++){
if(set.contains(c[i]))
continue;
set.add(c[i]);
swap(x,i);
dfs(x+1);
swap(x,i);
}
}
public void swap(int a,int b){
char temp=c[a];
c[a]=c[b];
c[b]=temp;
}
}
位運算
1 二進制1的個數
public int hammingWeight(int n) {
int count=0;
while(n!=0){
count+=n&1;
n=n>>>1;
}
return count;
}
2 數組中數字出現的次數1
public int[] singleNumbers(int[] nums) {
int x=nums[0];
for(int i=1;i<nums.length;i++)
x=x^nums[i];
int p=x&(-x);
int[] arr=new int[2];
for(int i=0;i<nums.length;i++){
if((nums[i]&p)==p)
arr[0]^=nums[i];
else
arr[1]^=nums[i];
}
return arr;
}
3 數組中數字出現的次數2
public int singleNumber(int[] nums) {
HashMap<Integer,Integer> map=new HashMap<>();
for(int n:nums){
if(map.containsKey(n))
map.put(n,map.get(n)+1);
else
map.put(n,1);
}
Set<Integer> integers = map.keySet();
for(int i:integers){
if(map.get(i)==1)
return i;
}
return -1;
}
4 計算1+2+…+n
短路與
public int sumNums(int n) {
boolean help=n>1&&(n+=sumNums(n-1))>1;
return n;
}
5 不用加減乘除做加法
public int add(int a, int b) {
while(b!=0){
int c=(a&b)<<1;
a^=b;
b=c;
}
return a;
}