算法分类汇总

数位 DP - OI Wiki

按照大纲把下面的题目刷完,并把代码烂熟于心,就几乎可以应对 90% 的面试算法考题了。

本篇内容包括如下模块:

  • 高频算法题系列:链表

  • 【🔥】【有真题】高频算法题系列:字符串

  • 【🔥】【有真题】高频算法题系列:数组问题

  • 高频算法题系列:二叉树

  • 【🔥】高频算法题系列:排序算法

  • 【🔥】高频算法题系列:二分查找

  • 【🔥】高频算法题系列:动态规划

  • 高频算法题系列:BFS

  • 【🔥】高频算法题系列:栈

  • 【🔥】高频算法题系列:DFS

  • 【🔥】高频算法题系列:回溯算法

其中标🔥的部分代表非常高频的考题,其中不乏笔者遇到的原题。其中对于每一类,首先会列出包含的考题,然后针对每一道考题会给出难度、考察知识点、是否是面试真题,在每道题详细介绍时,还会给出每道题的 LeetCode 链接,帮助读者理解题意,以及能够进行实际的测验,还可以观看其他人的答案,更好的帮助准备。

高频算法题系列:链表

笔者遇到的高频链表题主要包含这几道:

  • 通过快慢指针寻找链表中点 【简单】

  • 通过链表的后续遍历判断回文链表问题 【简单】

  • 链表的反向输出 【简单】

  • 合并 K 个升序链表 【困难】

  • K个一组翻转链表 【困难】

  • 环形链表 【简单】

  • 排序链表 【中等】

  • 相交链表 【简单】

寻找链表中点

题解

通过快慢指针寻找链表中点

/**
  *
  */
function findCenter(head) {
    let slower = head, faster = head;
    while (faster && faster.next != null) {
        slower = slower.next;
        faster = faster.next.next;
    }
    // 如果 faster 不等于 null,说明是奇数个,slower 再移动一格
    if (faster != null) {
        slower = slower.next;
    }
    return slower;
}

前序遍历判断回文链表

👉 【LeetCode 直通车】:234 回文链表(简单)[1]

题解1

利用链表的后续遍历,使用函数调用栈作为后序遍历栈,来判断是否回文

class Solution {
//方法2,倒叙遍历链表和正顺遍历链表
ListNode left;
boolean isPalindrome=true;
 public boolean isPalindrome(ListNode head) {
     this.left=head;
     isPalindromeDFS(head);
    return this.isPalindrome;

 }
  public void isPalindromeDFS(ListNode right){
      if(right==null){
          return;
      }
      isPalindromeDFS(right.next);
      if(right.val!=this.left.val){
          this.isPalindrome=false;
          return;
      }
      if(this.left!=null){
          this.left=this.left.next;
      }
    
  }


//    public boolean isPalindrome(ListNode head) {
// 		  ListNode fast=head,slow=head;
// 		  while(fast!=null&&fast.next!=null){
// 			  slow=slow.next;
// 			  fast=fast.next.next;
// 		  }
// 		  ListNode  lastNodes=null;
// 		  if(fast==null){
// 			    lastNodes=reverseNode2(slow);
// 		  }else{
// 			    lastNodes=reverseNode2(slow.next);
// 		  }
// 		  while(lastNodes!=null){
// 			  if(head.val!=lastNodes.val){
// 				  return false;
// 			  }
// 			  head=head.next;
// 			  lastNodes=lastNodes.next;
			  
// 		  }
// 		return true;
// 	    }
// 	  public static  ListNode reverseNode2(ListNode head){
//            if(head==null){
// 			  return null;
// 		  }
// 		  if(head.next==null){
// 			  return head;
// 		  }
// 		  ListNode next=head.next;
// 		  ListNode node=reverseNode2(next);
// 		  next.next=head;
// 		  head.next=null;
// 		  return node;
		  
// 	  }
	
}

反转链表

👉 【LeetCode 直通车】:206 反转链表(简单)[2]

题解

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    if (head == null || head.next == null) return head;
    let last = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return last;
};

方法2
 public ListNode reverseList(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode pre=null,cur=head,next=head.next;
        while(cur!=null){
            next=cur.next;
            cur.next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
 }

合并K个升序链表

👉 【LeetCode 直通车】:23 合并K个升序链表(困难)[3]

347. 前 K 个高频元素

题解

public ListNode mergeKLists(ListNode[] lists) {
	
	PriorityQueue<ListNode> pr=new PriorityQueue<ListNode>(new Comparator<ListNode>(){
        public int compare(ListNode o1,ListNode o2){
            return o1.val-o2.val;
        }
    });
	ListNode head=new ListNode();
	ListNode tail =head;
	if(lists==null||lists.length==0){
		return head.next;
	}
	for(ListNode temp:lists){
		if(temp!=null){
			pr.add(temp);
		}
		
	}
	
	while(!pr.isEmpty()){
		ListNode tempNode=pr.poll();
		tail.next=tempNode;
		tail =tail.next;
		if(tempNode.next!=null)
		pr.offer(tempNode.next);
		
	}
	return head.next;
	
}

92. 反转链表 II

class Solution {
public ListNode nextNewNode=null;
 public ListNode reverseBetween(ListNode head, int left, int right) {
        if(head==null){
            return null;
        }
        if(right==0){
            return head;
        }
        if(left==1){
            return reverseNodesK(head,right);
        }else{
            head.next=reverseBetween(head.next,left-1,right-1);
            return head;
        }
 }
    ListNode reverseNodesK(ListNode head,int k){
        if(head==null||head.next==null){
            return head;
        }
        if(k==1){
            this.nextNewNode=head.next;
            return head;
        }
        ListNode next=head.next;
        ListNode resultNode=reverseNodesK(next,k-1);
        next.next=head;
        head.next=nextNewNode;
        return resultNode;
    }
 
}

K 个一组翻转链表

👉 【LeetCode 直通车】:25 K 个一组翻转链表(困难)[4]

题解

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head==null||k==0){
            return head;
        }
        ListNode tail =head;
        for(int i=0;i<k;i++){
            if(tail==null){
                return head;
            }
            tail =tail.next;
        }
        ListNode newHead=reverseNodeAB(head,tail);
        head.next=reverseKGroup(tail,k);
        return newHead;

    }
    public  ListNode reverseNodeAB(ListNode a,ListNode b){
        if(a.next==b){
            return a;
        }
        ListNode next=a.next;
        ListNode newHead=reverseNodeAB(a.next,b);
        next.next=a;
        a.next=null;
        return newHead;

    }
    // public  ListNode reverseNodeAB(ListNode a,ListNode b){
    //     ListNode pre=null,next=null,cur=a;
    //     while(cur!=b){
    //         next=cur.next;
    //         cur.next=pre;
    //         pre=cur;
    //         cur=next;
    //     }
    //     return pre;
    // }
}

环形链表

👉 【LeetCode 直通车】:141 环形链表(简单)[5]

题解

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    if (head == null || head.next == null) return false;
    let slower = head, faster = head;
    while (faster != null && faster.next != null) {
        slower = slower.next;
        faster = faster.next.next;
        if (slower === faster) return true;
    }
    return false;
};

142. 环形链表 II

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode faster=head,slower=head;
        while(faster!=null&&faster.next!=null){
            faster=faster.next.next;
            slower=slower.next;
            if(faster==slower){
                slower=head;
                while(slower!=faster){
                    slower=slower.next;
                    faster=faster.next;
                }
                return faster;
            }
        }
        return null;
        
    }
}

排序链表

👉 【LeetCode 直通车】:148 排序链表(中等)[6]

题解

class Solution {
     public ListNode sortList(ListNode head) {
    	if(head==null||head.next==null){
    		return head;
    	}
    	ListNode middleNode=findMiddle(head);
    	ListNode nextList=middleNode.next;
    	middleNode.next=null;
    	ListNode sortedList1=sortList(head);
    	ListNode sortedList2=sortList(nextList);
    	return mergeSortedList(sortedList1,sortedList2);
    	
    	

    }
    public ListNode findMiddle(ListNode head){
    	ListNode faster=head,slower=head;
        if(faster!=null&&faster.next!=null&&faster.next.next==null){
            return faster;
        }
    	while(faster!=null&&faster.next!=null){
    		faster=faster.next.next;
    		slower=slower.next;
    	}
    	return slower;
    }
    
    public ListNode mergeSortedList(ListNode a,ListNode b){
    	ListNode head=new ListNode(0);
    	ListNode tail=head;
    	while(a!=null&&b!=null){
    		if(a.val>b.val){
    			tail.next=b;
    			tail=tail.next;
    			b=b.next;
    		}else{
    			tail.next=a;
    			tail=tail.next;
    			a=a.next;
    		}
    	}
    	if(a==null){
    		tail.next=b;
    	}else{
    		tail.next=a;
    	}
    	return head.next;
    }
    
}

相交链表

👉 【LeetCode 直通车】:160 相交链表(简单)[7]

题解

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode tempA=headA,tempB=headB;
        int i=0;
        while(tempA!=tempB){
            tempA=tempA.next;
            tempB=tempB.next;
            if(tempA==null){
                tempA=headB;
                i++;
            }
            if(tempB==null){
                tempB=headA;
                i++;
            }
            if(i>=3){
                return null;
            }
        }
        return tempA;
        
    }
}

【🔥】高频算法题系列:字符串

主要有以下几类高频考题:

  • 最长回文子串 【中等】【双指针】【面试真题】

  • 最长公共前缀 【简单】【双指针】

  • 无重复字符的最长子串【中等】【双指针】

  • 最小覆盖子串 【困难】【滑动窗口】【面试真题】

  • 424. 替换后的最长重复字符

【面试真题】最长回文子串【双指针】

👉 【LeetCode 直通车】:5 最长回文子串(中等)[8]

题解

class Solution {
   	   
	    public String longestPalindrome(String s) {
            int maxLength=0;
	        String longestPalindromeStr="";
			  if(s==null||s.length()==0){
                  return null;
              }
               if(s.length()==1){
                  return s;
              }
              int dp[][]=new int[s.length()][s.length()];
              for(int i=0;i<s.length();i++){
                  dp[i][i]=1;
                  for(int j=0;j<i;j++){
                      if(i-j==1){
                          dp[j][i]=s.charAt(i)==s.charAt(j)?2:0;
                      }else{
                          if(dp[j+1][i-1]>0&&s.charAt(i)==s.charAt(j)){
                               dp[j][i]=dp[j+1][i-1]+2;
                          }
                      }
                      if(dp[j][i]>maxLength){
                          maxLength=dp[j][i];
                          longestPalindromeStr=s.substring(j,i+1);
                      }
                  }

              }
                if(maxLength==0){
                    return s.substring(0,1);
                }

              return longestPalindromeStr;
	    }
	

    //   public int longestPalindrome=0;
    //   public String longestPalindromeStr;
	//   public String longestPalindrome(String s) {
    //       if(s==null||s.length()==0){
    //           return null;
    //       }
    //       for(int i=0;i<s.length();i++){
    //         longestPalindromeDFS(s,i,i);
    //         longestPalindromeDFS(s,i,i+1);
    //       }
    //       return longestPalindromeStr;

		 
	//     }
	//   public void longestPalindromeDFS(String s ,int start1,int start2){
    //       while(s!=null&&start1>=0&&start2<s.length()&&s.charAt(start1)==s.charAt(start2)){
    //           start1--;
    //           start2++;
    //       }
    //       if(start2-start1>longestPalindrome){
    //           longestPalindrome=start2-start1;
    //           longestPalindromeStr=s.substring(start1+1,start2);
    //       }

    //   }
	
}

516. 最长回文子序列

class Solution {

    public int longestPalindromeSubseq(String s) {

        int m=s.length();

        int [][]dp=new int[m][m];

        for(int i=0;i<m;i++){

            dp[i][i]=1;

            for(int j=i-1;j>=0;j--){

                if(s.charAt(i)==s.charAt(j)){

                    dp[j][i]=dp[j+1][i-1]+2;

                }else{

                    dp[j][i]=Math.max(dp[j][i-1],dp[j+1][i]);

                }

            }

        }

        return dp[0][m-1];

    }

}

最长公共前缀【双指针】

👉 【LeetCode 直通车】:14 最长公共前缀(简单)[9]

题解

class Solution {
    public String longestCommonPrefix(String[] strs) {
        String longestCommonPrefix=strs[0];
        for(int i=1;i<strs.length;i++){
            longestCommonPrefix=twoCommonPrefix(longestCommonPrefix,strs[i]);
            if(longestCommonPrefix==null){
                break;
            }
        }
        return longestCommonPrefix;

    }


    public String twoCommonPrefix(String s1,String s2){
        int index=0;
        while(index<s1.length()&&index<s2.length()&&s1.charAt(index)==s2.charAt(index)){
            index++;
        }
        return s1.substring(0,index);
    }
}

无重复字符的最长子串【双指针】

209. 长度最小的子数组

283. 移动零(双指针)

👉 【LeetCode 直通车】:3 无重复字符的最长子串(中等)[10]

题解

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int left=0,right=0;
        int maxLength=0;
        if(s==null||"".equals(s)){
            return 0;
        }
         if(s.length()==1){
            return 1;
        }
        Set<Character> set=new HashSet<Character>();
        for( ;right<s.length();right++){
            Character curChar=s.charAt(right);
            while(set.contains(curChar)){
                set.remove(s.charAt(left));
                left++;
            }
            set.add(curChar);
             maxLength=Math.max(maxLength,right-left+1);


        }
        return maxLength;

    }
}

【面试真题】 最小覆盖子串【滑动窗口】

1052. 爱生气的书店老板

1208. 尽可能使字符串相等

👉 【LeetCode 直通车】:76 最小覆盖子串(困难)[11]

题解

class Solution {
   public String minWindow(String s, String t) {
       if(s==null||t==null||s.length()<t.length()){
           return "";
       }
       Map<Character,Integer> mapT=new HashMap<Character,Integer>();
	   Map<Character,Integer> mapS=new HashMap<Character,Integer>();
       for(int i=0;i<t.length();i++){
           mapT.put(t.charAt(i),mapT.getOrDefault(t.charAt(i),0)+1);
       }
       int left=0,fitNum=0,right=0,minLength=Integer.MAX_VALUE;
       String minStr="";
       for(;right<s.length();right++){
           Character curChar=s.charAt(right);
           if(mapT.containsKey(curChar)){
                mapS.put(curChar,mapS.getOrDefault(curChar,0)+1);
                if(mapT.get(curChar).equals(mapS.get(curChar))){
                    fitNum++;
                }
                while(fitNum==mapT.keySet().size()){
                    if(right-left<minLength){
                        minLength=right-left;
                        minStr=s.substring(left,right+1);
                    }
                    char leftChar=s.charAt(left);
                    left++;
                    if(mapT.containsKey(leftChar)){
                        if(mapS.get(leftChar).equals(mapT.get(leftChar))){
                            fitNum--;
                        }
                        mapS.put(leftChar,mapS.get(leftChar)-1);
                        
                    }
                }

           }
       }
       return minStr;

	}
}

【🔥】高频算法题系列:数组问题

主要有几类高频考题:

  • 俄罗斯套娃信封问题【困难】【排序+最长上升子序列】【面试真题】

  • 最长连续递增序列 【简单】【双指针】

  • 最长连续序列【困难】【哈希表】

  • 盛最多水的容器【困难】【面试真题】

  • 寻找两个正序数组的中位数【困难】【双指针】

  • 删除有序数组中的重复项【简单】【快慢指针】

  • 和为K的子数组【中等】【哈希表】

  • nSum 问题【系列】【简单】【哈希表】

  • 接雨水【困难】【暴力+备忘录优化】【面试真题】

  • 跳跃游戏【系列】【中等】【贪心算法】

  • 915. 分割数组

【面试真题】俄罗斯套娃信封问题【排序+最长上升子序列】

👉 【LeetCode 直通车】:354 俄罗斯套娃信封问题(困难)[12]

题解

class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        Arrays.sort(envelopes,new Comparator<int[]>(){
            public int compare(int []o1,int[]o2){
                if(o1[0]!=o2[0]){
                    return o1[0]-o2[0];
                }else{
                    return o2[1]-o1[1];
                }
            }
        });
        int []dp=new int [envelopes.length];
        int result=0;
        for(int i=0;i<envelopes.length;i++){
            dp[i]=1;
            for(int j=0;j<i;j++){
                if(envelopes[i][1]>envelopes[j][1]){
                    dp[i]=Math.max(dp[i],dp[j]+1);
                }
            }
            result=Math.max(result,dp[i]);

        }
        return result;

    }
}

最长连续递增序列【快慢指针】

👉 【LeetCode 直通车】:674 最长连续递增序列(简单)[13]

题解

class Solution {
    public int findLengthOfLCIS(int[] nums) {
        if(nums==null||nums.length==0){
            return 0;
        }
        int tempResult=1;
        int result=1;
        for(int i=0;i<nums.length-1;i++){
            if(nums[i+1]>nums[i]){
                tempResult++;
            }else{
                tempResult=1;
            }
            result=Math.max(result,tempResult);
        }
        return result;

    }
}

最长连续序列 【哈希表】

👉 【LeetCode 直通车】:128 最长连续序列(困难)[14]

题解

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set=new HashSet<Integer>();
       for(int num:nums){
           set.add(num);
       }
        int result=0;
        for(int i=0;i<nums.length;i++){
            Integer curNum=nums[i];
            if(!set.contains(curNum-1)){
                int temp=1;
                while(set.contains(curNum+1)){
                    temp++;
                    curNum+=1;

                }
                result=Math.max(result,temp);
            }

        }
        return result;

    }
}

【面试真题】盛最多水的容器【哈希表】

👉 【LeetCode 直通车】:11 盛最多水的容器(中等)[15]

题解

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let n = height.length;
    let left = 0, right = n - 1;
    let maxOpacity = 0;
    while (left < right) {
        let res = Math.min(height[left], height[right]) * (right - left);
        maxOpacity = Math.max(maxOpacity, res);
        if (height[left] < height[right]) left++
        else right--;
    }
    return maxOpacity;
};

寻找两个正序数组的中位数【双指针】

👉 【LeetCode 直通车】:4 寻找两个正序数组的中位数(困难)[16]

题解

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m=nums1.length,n=num2.length;
        if(m>n){
            int []temp=nums1;
            nums1=nums2;
            nums2=temp;
        }
        m=nums1.length,n=num2.length;
        int totalLfetCount=n-(n-m+1)/2;
        int nums1LeftCount=0;
        int nums2LeftCount=0;
        int left=0;right=m-1;
        while(left<=right){
            int middle=right-(right-left)/2;
            int nums2Right=totalLfetCount-middle-1;
            if(nums1[nums1LeftCount-1]>nums2[nums2LeftCount]){
                right=nums1left-1;
            }else{
                left=nums1left+1;
            }

        }


    }
}

删除有序数组中的重复项【快慢指针】

👉 【LeetCode 直通车】:26 删除有序数组中的重复项(简单)[17]

题解

class Solution {
    public int removeDuplicates(int[] nums) {
      int slower=0,faster=0;
      while(faster<nums.length){
         if(nums[slower]!=nums[faster]){
             slower++;
             nums[slower]=nums[faster];
         }
         faster++;
      }
      return slower+1;

    }
}

👉 【LeetCode 直通车】:695 岛屿的最大面积(中等)[18]

题解

class Solution {
    public int maxAreaOfIsland=0;
    public int tempMaxAreaOfIsland=0;
    public int maxAreaOfIsland(int[][] grid) {
        int m=grid.length;
        int n=grid[0].length;
        boolean [][]used=new boolean[m][n];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(!used[i][j]&&grid[i][j]==1){
                    this.tempMaxAreaOfIsland=0;
                    maxAreaOfIslandDFS(grid,i,j,used);
                }
            }
        }
        return maxAreaOfIsland;
    }
    public void maxAreaOfIslandDFS(int[][]grid,int i,int j,boolean [][]used){
        if(i<0||i>grid.length-1||j<0||j>grid[0].length-1){
            return;
        }
        if(used[i][j]||grid[i][j]==0){
            return;
        }
        tempMaxAreaOfIsland++;
        maxAreaOfIsland=Math.max(maxAreaOfIsland,tempMaxAreaOfIsland);
        used[i][j]=true;

        maxAreaOfIslandDFS(grid,i+1,j,used);
        maxAreaOfIslandDFS(grid,i-1,j,used);
        maxAreaOfIslandDFS(grid,i,j-1,used);
        maxAreaOfIslandDFS(grid,i,j+1,used);

    }
}

和为K的子数组【哈希表】

437. 路径总和 III

1248. 统计「优美子数组」

974. 和可被 K 整除的子数组

👉 【LeetCode 直通车】:560 和为K的子数组(中等)[19]

题解

//所有以nums[i]为结尾的和为k的连续子数组,    j到i的连续子数组和为k,则0到j的和为(0到i的和减去k)
class Solution {
    public int subarraySum(int[] nums, int k) {
        if(nums==null||nums.length==0){
            return 0;
        }
        Map<Integer,Integer> mapResult=new HashMap<Integer,Integer>();
        int temp=0;
        int result=0;
        mapResult.put(0,1);
        for(int i=0;i<nums.length;i++){
            temp+=nums[i];
            if(mapResult.containsKey(temp-k)){
                result+=mapResult.get(temp-k);
            }
            mapResult.put(temp,mapResult.getOrDefault(temp,0)+1);

        }
        return result;

    }
}

nSum问题【哈希表】【系列】

  • 👉 【LeetCode 直通车】:1 两数之和(简单)[20]

  •     public int[] twoSum(int[] nums, int target) {
    		Map<Integer,Integer> map=new HashMap<Integer,Integer>();
            for(int i=0;i<nums.length;i++){
                if(map.containsKey(target-nums[i])){
                    return new int[]{map.get(target-nums[i]),i};
                }
                map.put(nums[i],i);
            }
            return new int[]{-1,-1};
        }
  • 👉 【LeetCode 直通车】:167 两数之和 II - 输入有序数组(简单)[21]

  •     public int[] twoSum(int[] numbers, int target) {
            int left=0,right=numbers.length-1;
            while(left<right){
                int sum=numbers[left]+numbers[right];
                if(sum==target){
                    return new int[]{left+1,right+1};
                }else if(sum>target){
                    right--;
                }else{
                    left++;
                }
            }
            return new int[]{-1,-1};
    
        }
  • 👉 【LeetCode 直通车】:15 三数之和(中等)[22]

  • 👉 【LeetCode 直通车】:18 四数之和(中等)[23]

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        return nSumDFS(nums,4,0,target);

    }
    public List<List<Integer>> nSumDFS(int []nums,int n,int start,int target){
        List<List<Integer>>  result=new ArrayList<List<Integer>>();
        if(n==2){
            int end=nums.length-1;
            while(start<end){
                if(nums[start]+nums[end]<target){
                    start++;
                    while(nums[start]==nums[start-1]&&start<end){
                        start++;
                    }
                }else if(nums[start]+nums[end]>target){
                    end--;
                     while(nums[end]==nums[end+1]&&start<end){
                        end--;
                    }
                }else{
                     List<Integer> twoSum=new ArrayList<Integer>();
                     twoSum.add(nums[start]);
                     twoSum.add(nums[end]);
                     result.add(twoSum);
                     start++;
                     end--;
                    while(start>0&&nums[start]==nums[start-1]&&start<end){
                        start++;
                    }
                     while(end<nums.length-1&&nums[end]==nums[end+1]&&start<end){
                        end--;
                    }

                }

            }

        }else{
             for(int i=start ;i<nums.length;i++){
                int curNum=nums[i];
               if(i>start&&nums[i]==nums[i-1]){
                    continue;
                }
                List<List<Integer>> tempResult=nSumDFS(nums,n-1,i+1,target-curNum);
                if(tempResult!=null&&tempResult.size()>0){
                    for(List<Integer> tempList:tempResult){
                        tempList.add(curNum);
                        result.add(tempList);
                    }
                }
             }

        }
       return result;


    }
}

接雨水【暴力+备忘录优化】

👉 【LeetCode 直通车】:42 接雨水(困难)[24]

题解

//     1.首先我们需要搞清楚,下标为i的雨水量是由什么决定的.
// 是由i左右两边最大值中较小的那个减去height[i]决定的.例 [0,1,0,2,1,0,1,3,2,1,2,1]中,下标为2的位置 值为0,而它的用水量是由左边的最大值1,右边最大值3 中较小的那个 也就是1减去0得到的。

// 2.本题解的双指针先找到当前维护的左、右最大值中较小的那个,例 当前 i 处左边的最大值如果比右边的小,那么就可以不用考虑 i 处右边最大值的影响了,因为 i 处 右边真正的最大值绝对比左边的最大值要大,在不断遍历时,更新max_l和max_r以及返回值即可。例 [0,1,0,2,1,0,1,3,2,1,2,1]中i=2时,值为0,此时max_l一定为1,当前max_r如果为2,即便max_r不是真正的i右边的最大值,也可忽略右边最大值的影响,因为右边真正的最大值一定比左边真正的最大值大。


   public int trap(int[] height) {
		 if(height==null||height.length==0){
			 return 0;
		 }
		 int result=0,left=0,right=height.length-1,leftMax=0,rightMax=0;
		 while(left<right){
			 int heightLeft=height[left];
			 int heightRight=height[right];
			 leftMax=Math.max(leftMax, heightLeft);
			 rightMax=Math.max(rightMax, heightRight);
			 if(leftMax<rightMax){
				 left++;
				 result+=(leftMax-heightLeft);
			 }else{
				 right--;
				 result+=(rightMax-heightRight);
			 }
		 }
		 return result;
		 
	 }


stack的方式


 public int trap(int[] height) {
        if(height==null||height.length==0){
            return 0;
        }
        Stack<Integer> stack=new Stack<Integer>();
        int result=0;
        for(int i=0;i<height.length;i++){
            if(stack.isEmpty()){
                stack.push(i);
            }else{
                while(!stack.isEmpty()&&height[i]>height[stack.peek()]){
                    int heightLow=height[stack.pop()];
                    if(stack.isEmpty()){
                        break;
                    }
                    int deep=Math.min(height[stack.peek()],height[i])-heightLow;
                    result+=(deep*(i-stack.peek()-1)); //此处必须是stack中最后一个值,不能上上一个弹出的,例如  0的时候,7和2之间的宽度,2的时候7和4之间的宽度  [4,2,0,7]

                }
                stack.push(i);
            }
        }
        return result;
      

    }

跳跃游戏【贪心算法】【系列】

  • 👉 【LeetCode 直通车】:55 跳跃游戏(中等)[25]

  • class Solution {
        // 这样以来,我们依次遍历数组中的每一个位置,并实时维护 最远可以到达的位置。对于当前遍历到的位置 xx,如果它在 最远可以到达的位置 的范围内,那么我们就可以从起点通过若干次跳跃到达该位置,因此我们可以用 x + \textit{nums}[x]x+nums[x] 更新 最远可以到达的位置。
        public boolean canJump(int[] nums) { 
    		if(nums==null||nums.length==0){
                return true;
            }
            int rightMost=nums[0];
            for(int i=1;i<nums.length;i++){
                if(i<=rightMost){
                    rightMost=Math.max(rightMost,i+nums[i]);
                }
    
            }
            return rightMost>=nums.length-1;
    	}
    	 
    
    
        //暴力破解法
       	// public boolean canJump;
    	//  public boolean canJump(int[] nums) {
    	// 	 if(nums==null||nums.length==0){
    	// 		 return false;
    	// 	 }
    	// 	 canJumpDFS(nums,0);
    	// 	 return canJump;
    	//     }
    	 
    	 
    	//  public void canJumpDFS(int[] nums,int start){
    	// 	 if(canJump==true){
    	// 		 return;
    	// 	 }
    	// 	 if(start>=nums.length-1){
    	// 		 canJump=true;
    	// 		 return;
    	// 	 }
    	// 	 for(int i=start+1;i<=start+nums[start];i++){
    	// 		 canJumpDFS(nums, i);
    	// 	 }
    		 
    	//  }
    	
    }
  • 👉 【LeetCode 直通车】:45 跳跃游戏 II(中等)[26]

受限于篇幅,这里只给出第一道题的代码模板,也是一面常考真题。

题解

class Solution {
    public int jump(int[] nums) {
       if(nums==null||nums.length<=1){
           return 0;
       }
       int end=nums[0],farthest=nums[0],step=1;
       for(int i=0;i<nums.length-1;i++){
           if(i<=farthest){
               farthest=Math.max(farthest,i+nums[i]);
           }
           if(i==end){
               step++;
               end=farthest;
           }

       }
       return step;

    }
}

高频算法题系列:二叉树

主要有以下几类高频考题:

  • 二叉树的最近公共祖先【简单】【二叉树】

  • 二叉搜索树中的搜索【简单】【二叉树】

  • 删除二叉搜索树中的节点【中等】【二叉树】

  • 完全二叉树的节点个数【中等】【二叉树】

  • 二叉树的锯齿形层序遍历【中等】【二叉树】

二叉树的最近公共祖先【二叉树】

👉 【LeetCode 直通车】:236 二叉树的最近公共祖先(简单)[27]

题解

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
TreeNode result;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    lowestCommonAncestorDFS(root,p,q);
    return result;

}
public boolean lowestCommonAncestorDFS(TreeNode root ,TreeNode p,TreeNode q){
    if(root==null){
        return false;
    }
    boolean inCurren=false;
    if(root.val==p.val||root.val==q.val){
        inCurren=true;
    }
    boolean inLeft=lowestCommonAncestorDFS(root.left,p,q);
    boolean inRight=lowestCommonAncestorDFS(root.right,p,q);
    if(inCurren&&(inLeft||inRight)){
        result=root;
    }
     if(inLeft&&inRight){
        result=root;
    }
    return inLeft||inRight||inCurren;
}

    // public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    //     if(root==null){
    //         return null;
    //     }
    //     TreeNode left=lowestCommonAncestor(root.left,p,q);
    //     TreeNode right=lowestCommonAncestor(root.right,p,q);
    //      if((root.val==p.val||root.val==q.val)&&(left!=null||right!=null)){
    //         return root;
    //     }
    //     if(left!=null&&right!=null){
    //         return root;
    //     }
    //     if(left!=null){
    //         return  left;
    //     }
    //     if(right!=null){
    //         return  right;
    //     }

    //      if(root.val==p.val||root.val==q.val){
    //         return root;
    //     }
    //     return null;
       
        
    // }
}

二叉搜索树中的搜索【二叉树】

👉 【LeetCode 直通车】:700 二叉搜索树中的搜索(简单)[28]

题解

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
      if(root==null){
          return null;
      }
      if(root.val==val){
          return root;
      }
      if(val>root.val){
          return searchBST(root.right,val);
      }else{
           return searchBST(root.left,val);
      }
        
    }
}

删除二叉搜索树中的节点【二叉树】

👉 【LeetCode 直通车】:450 删除二叉搜索树中的节点(中等)[29]

题解

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root==null){
            return null;
        }
        if(key>root.val){
            root.right=deleteNode(root.right,key);
        }else if(key<root.val){
            root.left=deleteNode(root.left,key);
        }else{
            if(root.left==null){
                return root.right;
            }
            if(root.right==null){
                return root.left;
            }
            TreeNode smallestRight=getSmallestRight(root.right);
            int temp=smallestRight.val;
            smallestRight.val=root.val;
            root.val=temp;
             root.right=deleteNode(root.right,key);

        }
        return root;
       
    }
   //获取右子树最小子树
   public TreeNode getSmallestRight(TreeNode root){
       if(root==null){
           return null;
       }
       while(root.left!=null){
           root=root.left;
       }
       return root;
   }
}

完全二叉树的节点个数【二叉树】

👉 【LeetCode 直通车】:222 完全二叉树的节点个数(中等)[30]

题解

class Solution {
    public int countNodes(TreeNode root) {
        if(root==null){
            return 0;
        }
        int leftHeight=0;
        TreeNode leftTree=root;
        while(leftTree.left!=null){
            leftTree=leftTree.left;
            leftHeight++;
        }
         int rightHeight=0;
        TreeNode rightTree=root;
        while(rightTree.right!=null){
            rightTree=rightTree.right;
            rightHeight++;
        }
        if(leftHeight==rightHeight){
            return (int)Math.pow(2,leftHeight+1)-1;
        }else{
            return 1+ countNodes(root.left)+countNodes(root.right);
        }
    }
}

二叉树的锯齿形层序遍历【二叉树】

👉 【LeetCode 直通车】:103 二叉树的锯齿形层序遍历(中等)[31]

题解

class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        Queue <TreeNode> queue=new LinkedList<TreeNode>();
        List<List<Integer>> result=new ArrayList<List<Integer>>();
        int index=1;
        if(root!=null){
            queue.offer(root);
        }
        while(!queue.isEmpty()){
            int size=queue.size();
            Deque<Integer> deque=new LinkedList<Integer>();
            for(int i=0;i<size;i++){
                    TreeNode curNode=queue.poll();
                    if(curNode.left!=null){
                        queue.offer(curNode.left);
                    }
                      if(curNode.right!=null){
                        queue.offer(curNode.right);
                    }
                    if(index%2==1){
                        deque.offerLast(curNode.val);
                    }else{
                         deque.offerFirst(curNode.val);
                    }
            }
            result.add(new ArrayList(deque));
            index++;
        }
        return result;

    }

 }

【🔥】高频算法题系列:排序算法

主要有以下几类高频考题:

  • 用最少数量的箭引爆气球【中等】【排序】

  • 合并区间【中等】【排序算法+区间问题】【面试真题】

用最少数量的箭引爆气球【排序算法】

👉 【LeetCode 直通车】:452 用最少数量的箭引爆气球(中等)[32]

题解

对比435. 无重叠区间

如果按左端升序排序,可能出现这种:[0, 9], [0, 6], [7, 8]

    当前第一个区间和第二个重合,我让当前第一个区间继续寻求重合,它和第三个也重合。
    你想着一箭三雕,但第二个和第三个其实并不重合。
    被「包含」在当前区间的重合区间,不一定和别的重合区间重合
    当前区间可能和很多区间重合,但无法保证这些区间内部都互相重合。

//尾部排序,每个开始和之前的结尾做对比,结尾是有序的,若采用头部排序,后面的头部和结尾比较,结尾无续,可能存在前面的尾部更长,后面两个尾部更短的情况 

class Solution {
    public int findMinArrowShots(int[][] points) {
        if(points==null){
            return 0;
        }
        Arrays.sort(points,new Comparator<int []>(){
            public int compare(int []o1,int []o2){
               return  Integer.compare(o1[1], o2[1]);
            }
        });
        int startIndex=points[0][1];
        int result=1;
        for(int i=1;i<points.length;i++){
            if(points[i][0]>startIndex){
                result++;
                startIndex=points[i][1];
            }
        }
        return result;
    }
}

合并区间【排序算法+区间问题】

👉 【LeetCode 直通车】:56 合并区间(中等)[33]

题解

class Solution {
     public int[][] merge(int[][] intervals) {
         if(intervals==null){
             return new int[][]{};
         }
         Arrays.sort(intervals,new Comparator<int[]>(){
             public int compare(int[]a,int[]b){
                 return Integer.compare(a[0],b[0]);
             }
         });
         List<int[]> result=new ArrayList<int[]>();
         result.add(intervals[0]);
         int maxRight=intervals[0][1];
        for(int i=1;i<intervals.length;i++){
            if(intervals[i][0]> result.get(result.size()-1)[1]){
                 result.add(intervals[i]);
            }else{
                result.get(result.size()-1)[1]=Math.max(intervals[i][1], result.get(result.size()-1)[1]);
            }

        }
        return result.toArray(new int [result.size()][]);

     }
}

高频算法题系列:二分查找

主要有以下几类高频考题:

  • 寻找两个正序数组的中位数【困难】【二分查找】

  • 判断子序列【简单】【二分查找】

  • 在排序数组中查找元素的第一个和最后一个位置【中等】【二分查找】

寻找两个正序数组的中位数【二分查找】

👉 【LeetCode 直通车】:4 寻找两个正序数组的中位数(困难)[34]

题解

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    let m = nums1.length, n = nums2.length;
    let i = 0, j = 0;
    let newArr = [];
    while (i < m && j < n) {
        if (nums1[i] < nums2[j]) {
            newArr.push(nums1[i++]);
        } else {
            newArr.push(nums2[j++]);
        }
    }
    newArr = newArr.concat(i < m ? nums1.slice(i) : nums2.slice(j));
    const len = newArr.length;
    console.log(newArr)
    if (len % 2 === 0) {
        return (newArr[len / 2] + newArr[len / 2 - 1]) / 2;
    } else {
        return newArr[Math.floor(len / 2)];
    }
};

判断子序列【二分查找】

👉 【LeetCode 直通车】:392 判断子序列(简单)[35]

题解

class Solution {
    public boolean isSubsequence(String s, String t) {
        if(s==null||t==null){
            return true;
        }
        int m=s.length(),n=t.length(),i=0,j=0;
        if(m>n){
            return false;
        }
        while(i<m&&j<n){
            if(s.charAt(i)==t.charAt(j)){
                i++;
            }
            j++;
        }
        return i==m;
    }
}

💁 在排序数组中查找元素的第一个和最后一个位置【二分搜索】

对比二分查找:875. 爱吃香蕉的珂珂

1011. 在 D 天内送达包裹的能力

69. Sqrt(x)

👉 【LeetCode 直通车】:34 在排序数组中查找元素的第一个和最后一个位置(中等)[36]

题解

class Solution {
    public int[] searchRange(int[] nums, int target) {
        if(nums==null||nums.length==0){
            return new int[]{-1,-1};
        }
        int left=binarySearch(nums,target,true);
         int right=binarySearch(nums,target,false);
         return new int[]{left,right};
        
    }
   public int binarySearch(int []nums,int target,boolean isFirst){
       int left=0,right=nums.length-1;
       while(left<=right){
           int middle=right-(right-left)/2;
           if(isFirst){
               if(target<=nums[middle]){
                   right=middle-1;
               }else{
                   left=middle+1;
               }
           }else{
               if(target>=nums[middle]){
                   left=middle+1;
               }else{
                   right=middle-1;
               }

           }
        
       }
        if(isFirst&&left<nums.length&&nums[left]==target){
            return left;
            
        }
          if(!isFirst&&right>=0&&nums[right]==target){
            return right;
            
        }
        return -1;
   }
}

【🔥】高频算法题系列:动态规划

主要有以下几类高频考题:

  • 最长递增子序列【中等】【动态规划】

  • 零钱兑换【中等】【动态规划】【面试真题】

  • 最长公共子序列 【中等】【动态规划】【面试真题】

  • 编辑距离 【困难】【动态规划】

  • 最长回文子序列【中等】【动态规划】【面试真题】

  • 最大子序和【简单】【动态规划】【面试真题】

  • 买卖股票的最佳时机系列【系列】【动态规划】【面试真题】

  • 801. 使序列递增的最小交换次数

  • 940. 不同的子序列 II

最长递增子序列【动态规划】

👉 【LeetCode 直通车】:300 最长递增子序列(中等)[37]

题解

class Solution {
// 考虑往]dp[0…i−1] 中最长的上升子序列后面再加一个 nums[i]。由于dp[j] 代表 nums[0…j] 中以 nums[j] 结尾的最长上升子序列,所以如果
   public int lengthOfLIS(int[] nums) {
		if(nums==null||nums.length==0){
            return 0;
        }
        int []dp=new int [nums.length];
        dp[0]=1;
        int result=0;
        for(int i=0;i<nums.length;i++){
            dp[i]=1;
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j]){
                    dp[i]=Math.max(dp[i],dp[j]+1);
                }
            }
            result=Math.max(result,dp[i]);
        }
        return result;

    }
	
}

【面试真题】 零钱兑换【动态规划】

👉 【LeetCode 直通车】:322 零钱兑换(中等)[38]

题解

class Solution {
    public int coinChange(int[] coins, int amount) {
         int dp[] =new int [amount+1];
         for(int i=1;i<=amount;i++){
             dp[i]=Integer.MAX_VALUE-1;
         }
         dp[0]=0;
        for(int coin:coins){
            for(int j=coin;j<=amount;j++){
                dp[j]=Math.min(dp[j],dp[j-coin]+1);

            }
        }
        return dp[amount]<(Integer.MAX_VALUE-1)?dp[amount]:-1;
    }
}

【面试真题】 最长公共子序列【动态规划】

👉 【LeetCode 直通车】:1143 最长公共子序列(中等)[39]

题解

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        if(text1==null||text2==null){
            return 0;
        }
        int dp[][]=new int[text1.length()+1][text2.length()+1];
        for(int i=1;i<=text1.length();i++){
            for(int j=1;j<=text2.length();j++){
                if(text1.charAt(i-1)==text2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                     dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }


            }
        }
        return dp[text1.length()][text2.length()];

    }
}

编辑距离【动态规划】

221. 最大正方形

👉 【LeetCode 直通车】:72 编辑距离(困难)[40]

题解

class Solution {
    public int minDistance(String word1, String word2) {
        int dp[][]=new int[word1.length()+1][word2.length()+1];
        for(int i=0;i<=word1.length();i++){
            dp[i][0]=i;
        }
        for(int i=0;i<=word2.length();i++){
            dp[0][i]=i;
        }
         for(int i=1;i<=word1.length();i++){
            for(int j=1;j<=word2.length();j++){
                if(word1.charAt(i-1)==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j]=Math.min(
                        Math.min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1]
                    )+1;
                }
            }
        }
        return dp[word1.length()][word2.length()];

    }
}

【面试真题】最长回文子序列【动态规划】

👉 【LeetCode 直通车】:516 最长回文子序列(中等)[41]

题解

class Solution {
    public int longestPalindromeSubseq(String s) {
        if(s==null||s.length()==0){
            return 0;
        }
        int [][]dp=new int[s.length()+1][s.length()+1];
        for(int i=0;i<s.length();i++){
            dp[i][i]=1;
        }
        for(int i=0;i<s.length();i++){
            for(int j=i-1;j>=0;j--){
                if(s.charAt(j)==s.charAt(i)){
                    dp[j][i]=dp[j+1][i-1]+2;
                }else{
                    dp[j][i]=Math.max(dp[j+1][i],dp[j][i-1]);
                }
            }
        }
        return dp[0][s.length()-1];
        
    }
}

【LeetCode 直通车】:5最长回文子串(中等)[41]

题解

class Solution {
   	   
	    public String longestPalindrome(String s) {
            int maxLength=0;
	        String longestPalindromeStr="";
			  if(s==null||s.length()==0){
                  return null;
              }
               if(s.length()==1){
                  return s;
              }
              int dp[][]=new int[s.length()][s.length()];
              for(int i=0;i<s.length();i++){
                  dp[i][i]=1;
                  for(int j=0;j<i;j++){
                      if(i-j==1){
                          dp[j][i]=s.charAt(i)==s.charAt(j)?2:0;
                      }else{
                          if(dp[j+1][i-1]>0&&s.charAt(i)==s.charAt(j)){
                               dp[j][i]=dp[j+1][i-1]+2;
                          }
                      }
                      if(dp[j][i]>maxLength){
                          maxLength=dp[j][i];
                          longestPalindromeStr=s.substring(j,i+1);
                      }
                  }

              }
                if(maxLength==0){
                    return s.substring(0,1);
                }

              return longestPalindromeStr;
	    }
	

    //   public int longestPalindrome=0;
    //   public String longestPalindromeStr;
	//   public String longestPalindrome(String s) {
    //       if(s==null||s.length()==0){
    //           return null;
    //       }
    //       for(int i=0;i<s.length();i++){
    //         longestPalindromeDFS(s,i,i);
    //         longestPalindromeDFS(s,i,i+1);
    //       }
    //       return longestPalindromeStr;

		 
	//     }
	//   public void longestPalindromeDFS(String s ,int start1,int start2){
    //       while(s!=null&&start1>=0&&start2<s.length()&&s.charAt(start1)==s.charAt(start2)){
    //           start1--;
    //           start2++;
    //       }
    //       if(start2-start1>longestPalindrome){
    //           longestPalindrome=start2-start1;
    //           longestPalindromeStr=s.substring(start1+1,start2);
    //       }

    //   }
	
}

【面试真题】💁 最大子序和【动态规划】

对比152. 乘积最大子数组

👉 【LeetCode 直通车】:53 最大子序和(简单)[42]

题解

class Solution {
     public int maxSubArray(int[] nums) {
         int dp[] =new int[nums.length];  //状态不能定义为前i个连续子数组,状态转移时 i和i-1未必连续,定位为以i为结尾的连续子数组
         if(nums==null||nums.length==0){
             return 0;
         }
         int maxSubArray=nums[0];
         dp[0]=nums[0];
         for(int i=1;i<nums.length;i++){
             dp[i]=Math.max(nums[i],dp[i-1]+nums[i]);
             maxSubArray=Math.max(maxSubArray,dp[i]);
         }
         return maxSubArray;

     }
    // public int maxSubArray(int[] nums) {
    //     if(nums==null||nums.length==0){
    //         return 0;
    //     }
    //     int tempSum=0,result=Integer.MIN_VALUE;
    //     for(int num:nums){
    //         tempSum+=num;
    //         if(tempSum>0){  //和大于0,就对后边新的数组有增益,可继续加
    //             result=Math.max(result,tempSum);
    //         }else{
    //             result=Math.max(result,tempSum);
    //             tempSum=0;
    //         }
    //     }
    //     return result;

    // }
}

【面试真题】💁 买卖股票的最佳时机【动态规划】

  • 👉 【LeetCode 直通车】:121 买卖股票的最佳时机(简单)[43]【面试真题】

  • class Solution {
        public int maxProfit(int[] prices) {
            int minValue=Integer.MAX_VALUE,result=0;
            if(prices==null||prices.length==1){
                return 0;
            }
            for(int price :prices){
                minValue=Math.min(minValue,price);
                result=Math.max(result,price-minValue);
            }
            return result;
    
        }
    }
  • 👉 【LeetCode 直通车】:122 买卖股票的最佳时机 II(简单)[44]

  • class Solution {
    
        // //贪心算法,画个走势上升下降图,每个上升阶段最高点和最低点差值,相当于中间各个点差值相加
        // public int maxProfit(int[] prices) {
        //     if(prices==null||prices.length<2){
        //         return 0;
        //     }
        //     int result=0;
        //     for(int i=1;i<prices.length;i++){
        //         if(prices[i]>prices[i-1]){
        //             result+=(prices[i]-prices[i-1]);
        //         }
        //     }
        //     return result;
    
        // }
    
     public int maxProfit(int[] prices) {
          if(prices==null||prices.length<2){
                return 0;
            }
    		int [][]dp=new int[prices.length][2];  //当前持有股票和未持有股票两种情况
    		dp[0][0]=0;
    		dp[0][1]=-prices[0];
    		for(int i=1;i<prices.length;i++){
    			dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);  //当前未持有的最大收益,上一步就未持有,上一步持有,到当前股票价格时卖掉
    			dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);  //当前持有最大收益为  上一步持有或者上一步未持有,现在买入
    		}
    		return Math.max(dp[prices.length-1][0], dp[prices.length-1][1]);
    	     
    	 }
    
    
    }
  • 👉 【LeetCode 直通车】:123 买卖股票的最佳时机 III(困难)[45]

  • 👉 【LeetCode 直通车】:188 买卖股票的最佳时机IV(困难)[46]

  • 👉 【LeetCode 直通车】:309 买卖股票的最佳时机含冷冻期(中等)[47]

  • class Solution {
        public int maxProfit(int[] prices) {
                    if(prices==null||prices.length<1){
                        return 0;
                    }
    		        int n=prices.length;
    		        int dp [][]=new int [n][3];
    		        //   [i][0]表示今天过后处于冻结未持有,[i][1]表持今天过后持有 ,[i][2] 表示处于非冻结可以买入期
    		        dp [0][1]=-prices[0];
    		      for(int i=1;i<prices.length;i++){
                       //今天过后处于锁定期的话,昨天过后必然处于买入期,并且今天卖出
                      dp[i][0]=dp[i-1][1]+prices[i];
                      //今天过后处于持有期的话,昨天持有,或者昨天可买入期并且今天买入
                      dp[i][1]=Math.max(dp[i-1][1],dp[i-1][2]-prices[i]);
                       //今天过后处于可买期的话,昨天过后可能处于锁定期或者昨天过后本身就是可买期
                      dp[i][2]=Math.max(dp[i-1][2],dp[i-1][0]);
    
                  }
                  return Math.max(Math.max(dp[prices.length-1][0],dp[prices.length-1][1]),dp[prices.length-1][2]);
    
    		    }
    }
  • 👉 【LeetCode 直通车】:714 买卖股票的最佳时机含手续费(中等)[48]

受限于篇幅,这里只给出第一道题的代码模板,也是一面常考真题,笔者在面试字节跳动时就遇到过。

题解

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  let dp = [];
  for (let i = -1; i < prices.length; i++) {
    dp[i] = []
    for (let j = 0; j <= 1; j++) {
      dp[i][j] = [];
      dp[i][j][0] = 0;
      dp[i][j][1] = 0;
      if (i === -1) {
        dp[i][j][1] = -Infinity;
      }
      if (j === 0) {
        dp[i][j][1] = -Infinity;
      }
      if (j === -1) {
        dp[i][j][1] = -Infinity;
      }
    }
  }
  for (let i = 0; i < prices.length; i++) {
    for (let j = 1; j <= 1; j++) {
      dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
      dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
    }
  }
  return dp[prices.length - 1][1][0];
};

801. 使序列递增的最小交换次数

class Solution {
    public int minSwap(int[] nums1, int[] nums2) {
        int n = nums1.length;
        int a = 0, b = 1;
        for (int i = 1; i < n; i++) {
            int at = a, bt = b;
            a = b = n;
            if (nums1[i] > nums1[i - 1] && nums2[i] > nums2[i - 1])  {
                a = Math.min(a, at);
                b = Math.min(b, bt + 1);
            }
            if (nums1[i] > nums2[i - 1] && nums2[i] > nums1[i - 1]) {
                a = Math.min(a, bt);
                b = Math.min(b, at + 1);
            }
        }
        return Math.min(a, b);
    }
}

高频算法题系列:BFS

主要有以下几类高频考题:

  • 打开转盘锁【中等】【BFS】

  • 二叉树的最小深度【简单】【BFS】

打开转盘锁【BFS】

👉 【LeetCode 直通车】:752 打开转盘锁(中等)[49]

题解

class Solution {
   	 public int openLock(String[] deadends, String target) {
		 	Set<String> lockSet=new HashSet<String>();
		 	Set<String> visited=new HashSet<String>();
		 	for(String curLock:deadends){
		 		lockSet.add(curLock);
		 	}
		 	Deque<String> queue=new LinkedList<String>();
		 	queue.offer("0000");
		 	// visited.add("0000");
		 	int minLength=0;
		 	while(!queue.isEmpty()){
		 		int length=queue.size();
		 		for(int j=0;j<length;j++){
		 			String curstring=queue.poll();
		 			if(lockSet.contains(curstring)||visited.contains(curstring)){
	 					continue;
	 				}
	 				if(target.equals(curstring)){
	 					return minLength;
	 				}
	 				visited.add(curstring);
		 			for(int i=0;i<4;i++){
		 				String plusString=plusOne(curstring,i);
		 				queue.offer(plusString);
		 				String minusString=minusOne(curstring,i);
		 				queue.offer(minusString);
				 	}
		 			
		 		}
		 		minLength++;
		 	}
		 	return -1;
		 	
	    }
	 
	 
	 
	 public String plusOne(String s,int index){
		 char[] charArray=s.toCharArray();
		 if(charArray[index]=='9'){
			 charArray[index]='0';
		 }else{
			 charArray[index]+=1;
		 }
		 return new String(charArray);
	 }
	
	 public String minusOne(String s,int index){
		 char[] charArray=s.toCharArray();
		 if(charArray[index]=='0'){
			 charArray[index]='9';
		 }else{
			 charArray[index]-=1;
		 }
		 return new String(charArray);
	 }
}

二叉树的最小深度【BFS】

👉 【LeetCode 直通车】:111 二叉树的最小深度(简单)[50]

题解

class Solution {
    public int minDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        Deque<TreeNode> queue=new LinkedList<TreeNode>();
        queue.offer(root);
        int minDeep=1;
        while(!queue.isEmpty()){
            int length=queue.size();
            for(int i=0;i<length;i++){
                TreeNode curNode=queue.poll();
                if(curNode.left==null&&curNode.right==null){
                    return   minDeep;
                }
                if(curNode.left!=null){
                    queue.offer(curNode.left);
                }
                if(curNode.right!=null){
                    queue.offer(curNode.right);
                }
            }
            minDeep++;
        }
        return minDeep;

    }
}

【🔥】高频算法题系列:栈

主要有以下几类高频考题:

  • 最小栈【简单】【栈】

  • 有效的括号【中等】【栈】【面试真题】

  • 简化路径【中等】【栈】

  • 下一个更大元素 【系列】【栈】

227. 基本计算器 II(点击看题)

1006. 笨阶乘

769. 最多能完成排序的块

最小栈【栈】

👉 【LeetCode 直通车】:155 最小栈(简单)[51]

题解

class MinStack {
    Stack <Integer> stack;
    Stack <Integer> minStack;

    /** initialize your data structure here. */
    public MinStack() {
        stack=new Stack<Integer>();
        minStack=new Stack<Integer>();

    }
    
    public void push(int val) {
        stack.push(val);
        minStack.push(minStack.isEmpty()?val:Math.min(minStack.peek(),val));

    }
    
    public void pop() {
        stack.pop();
        minStack.pop();

    }
    
    public int top() {
        return stack.peek();

    }
    
    public int getMin() {
        return minStack.peek();

    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

【系列】下一个更大元素 【栈】

  • 👉 【LeetCode 直通车】:496 下一个更大元素 I(简单)[52]

  • 👉 【LeetCode 直通车】:503 下一个更大元素 II(中等)[53]

受限于篇幅,这里只给出第一道题的代码模板

题解

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
      Map<Integer,Integer> map=new HashMap<Integer,Integer>();
      Stack<Integer> stack=new Stack<Integer>();
      int []result=new int[nums1.length];
      for(int i=nums2.length-1;i>=0;i--){
          while(!stack.isEmpty()&&nums2[i]>stack.peek()){
              stack.pop();
          }
          int iResult=stack.isEmpty()?-1:stack.peek();
          stack.push(nums2[i]);
          map.put(nums2[i],iResult);
      }
      for(int i=0;i<nums1.length;i++){
          result[i]=map.get(nums1[i]);

      }
      return result;

    }
}
下一个更大的元素2   罗列两遍数组

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        Stack<Integer> stack=new Stack<Integer>();
        int n=nums.length;
        int [] result=new int[n];
        for(int i=2*n-1;i>=0;i--){
            int index=i%n;
            while(!stack.isEmpty()&&stack.peek()<=nums[index]){
                stack.pop();
            }
            int curValue=stack.isEmpty()?-1:stack.peek();
            stack.push(nums[index]);
            result[index]=curValue;
        }
        return result;

    }
}

【面试真题】有效的括号【栈】

👉 【LeetCode 直通车】:20 有效的括号(中等)[54]

题解

class Solution {
     public static  boolean isValid(String s) {
		 if(s==null||s.length()==0){
			 return true;
		 }
		 while(s.contains("()")||s.contains("{}")||s.contains("[]")){
			s=s.replace("()", "");
			s=s.replace("{}", "");
			s=s.replace("[]", "");
		 }
		 return s.length()>0?false:true;
	    }



    // public static  boolean isValid(String s) {
	// 	 if(s==null||s.length()==0){
	// 		 return true;
	// 	 }
	// 	 Stack<Character> stack=new Stack<Character>();
	// 	 for(int i=0;i<s.length();i++){
	// 		 char curChar=s.charAt(i);
	// 		 if(curChar=='{'||curChar=='['||curChar=='('){
	// 			 stack.push(curChar);
	// 		 }else{
    //              if(stack.isEmpty()){
    //                  return false;
    //              }
	// 			 Character  leftChar=stack.pop();
	// 			 if(leftChar!=null&&leftChar=='{'&&curChar=='}'){
	// 				 continue;
	// 			 }else if(leftChar!=null&&leftChar=='['&&curChar==']'){
	// 				 continue;
	// 			 }else if(leftChar!=null&&leftChar=='('&&curChar==')'){
	// 				 continue;
	// 			 }else{
	// 				 return false;
	// 			 }
	// 		 }
	// 	 }
	// 	 return stack.size()>0?false:true;
	// }
}

简化路径【栈】

👉 【LeetCode 直通车】:71 简化路径(中等)[55]

题解

class Solution {
    public String simplifyPath(String path) {
        if(path==null||"".equals(path)){
            return "/";
        }
        String [] pathArray=path.split("/");
        Stack<String> stack=new Stack<String>();
        for(int i=0;i<pathArray.length;i++){
            String curString =pathArray[i];
            if(".".equals(curString)||"".equals(curString)){
                continue;
            }else if("..".equals(curString)&&!stack.isEmpty()){
                stack.pop();
            } else if("..".equals(curString)&&stack.isEmpty()){
                // return "/";
            }else{
                stack.push(curString);
            }
        }
      
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<stack.size();i++){
            sb.append("/");
            sb.append(stack.get(i));
        }
        return sb.length()==0?"/":sb.toString();
    }
}

【🔥】高频算法题系列:DFS

主要有以下几类高频考题:

  • 岛屿的最大面积【中等】【DFS】

  • 相同的树【简单】【DFS】

岛屿的最大面积【DFS】

👉 【LeetCode 直通车】:695 岛屿的最大面积(中等)[56]

题解

class Solution {
    public int maxAreaOfIsland=0;
    public int tempMaxAreaOfIsland=0;
    public int maxAreaOfIsland(int[][] grid) {
        int m=grid.length;
        int n=grid[0].length;
        boolean [][]used=new boolean[m][n];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(!used[i][j]&&grid[i][j]==1){
                    this.tempMaxAreaOfIsland=0;
                    maxAreaOfIslandDFS(grid,i,j,used);
                }
            }
        }
        return maxAreaOfIsland;
    }
    public void maxAreaOfIslandDFS(int[][]grid,int i,int j,boolean [][]used){
        if(i<0||i>grid.length-1||j<0||j>grid[0].length-1){
            return;
        }
        if(used[i][j]||grid[i][j]==0){
            return;
        }
        tempMaxAreaOfIsland++;
        maxAreaOfIsland=Math.max(maxAreaOfIsland,tempMaxAreaOfIsland);
        used[i][j]=true;

        maxAreaOfIslandDFS(grid,i+1,j,used);
        maxAreaOfIslandDFS(grid,i-1,j,used);
        maxAreaOfIslandDFS(grid,i,j-1,used);
        maxAreaOfIslandDFS(grid,i,j+1,used);

    }
}

相同的树【DFS】

👉 【LeetCode 直通车】:100 相同的树(简单)[57]

题解

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if((p!=null&&q!=null)&&(p.val==q.val)){
            return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
        }else if(p==null&&q==null){
            return true;
        }else{
            return false;
        }

    }
}

【🔥】高频算法题系列:回溯算法

主要有以下几类高频考题:

  • N皇后【困难】【回溯算法】【面试真题】

  • 全排列【中等】【回溯算法】

  • 括号生成【中等】【回溯算法】

  • 复原 IP 地址【中等】【回溯算法】

  • 子集 【简单】【回溯算法】

【面试真题】N皇后【回溯算法】

👉 【LeetCode 直通车】:51 N皇后(困难)[58]

题解

class Solution {
    List<List<String>> result=new ArrayList<List<String>>();
    public List<List<String>> solveNQueens(int n) {
        char [][] queenChar=new char[n][n];
        for(int i=0;i<n;i++){
            Arrays.fill(queenChar[i],'.');
        }
        solveNQueensDFS(queenChar,0);
        return result;



    }
    public void solveNQueensDFS(char[][]queenChar,int colIndex){
        if(colIndex>queenChar.length){
            return;  //理论上不可能>n,有所有rowIndex都不满足的,就没有深度遍历了
        }
        if(colIndex==queenChar.length){
            result.add(arrayToList(queenChar));
        }
        //在本行的所有列都暴力遍历一遍
        for(int i=0;i<queenChar.length;i++){
            if(isLegal(queenChar,colIndex,i)){
                queenChar[colIndex][i]='Q';
                solveNQueensDFS(queenChar,colIndex+1);
                 queenChar[colIndex][i]='.';
            }else{
                continue;
            }

        }

    }
    public boolean isLegal(char[][]queenChar,int colIndex,int rowIndex){
        //上方
        for(int i=colIndex-1;i>=0;i--){
            if(queenChar[i][rowIndex]=='Q'){
                return false;
            }
        }
         //左上角
        for(int i=colIndex-1,j=rowIndex-1;i>=0&&j>=0;i--,j--){
            if(queenChar[i][j]=='Q'){
                return false;
            }
        }

         //右上角
        for(int i=colIndex-1,j=rowIndex+1;i>=0&&j<queenChar.length;i--,j++){
            if(queenChar[i][j]=='Q'){
                return false;
            }
        }
        return true;
    }

    public List<String> arrayToList(char [][]queenChar){
        List<String> result=new ArrayList<String>();
        for(char [] tempChar:queenChar){
            String s=new String(tempChar);
            result.add(s);
        }
        return result;
    }
}

全排列【回溯算法】

👉 【LeetCode 直通车】:46 全排列(中等)[59]

题解

class Solution {
    List<List<Integer>> result=new ArrayList<List<Integer>>();
    public List<List<Integer>> permute(int[] nums) {
        if(nums==null||nums.length==0){
            return new ArrayList();
        }
        permuteDFS(nums,new ArrayList<Integer>(),new boolean [nums.length]);
        return result;
    }
    public void permuteDFS(int []nums,List<Integer> tempList,boolean[]used){
        if(tempList.size()==nums.length){
            result.add(new ArrayList(tempList));
            return;
        }
        for(int i=0;i<nums.length;i++){
            if(used[i]){
                continue;
            }
            tempList.add(nums[i]);
            used[i]=true;
            permuteDFS(nums,tempList,used);
             used[i]=false;
            tempList.remove(tempList.size()-1);
        }


    }
}

括号生成【回溯算法】

👉 【LeetCode 直通车】:22 括号生成(中等)[60]

题解


class Solution {
        List<String> list = new ArrayList<>();
    public List<String> generateParenthesis(int n) {
        if(n==0){
            return new ArrayList();
        }
        generateParenthesisDFS(n,0,0,"");
        return list;
      
    }
   public void generateParenthesisDFS(int n,int l,int right,String tempStr){
        if(l==right&&l==n){
            list.add(tempStr);
        }
        if(l<n){
            generateParenthesisDFS(n,l+1,right,tempStr+"(");
        }
        if(right<l){
            generateParenthesisDFS(n,l,right+1,tempStr+")");
        }

    }

   
}

复原 IP 地址【回溯算法】

👉 【LeetCode 直通车】:93 复原 IP 地址(中等)[61]

题解

class Solution {
    List<String> result=new ArrayList<String>();
    public List<String> restoreIpAddresses(String s) {
        if(s==null||s.length()==0){
            return result;
        }
        restoreIpAddressesDFS(0,s,4,"");
        return result;
    }
    public void restoreIpAddressesDFS(int startIndex,String s,int n,String tempS){
        if(startIndex==s.length()&&n==0){
            result.add(tempS);
        }
        if(startIndex==s.length()){
            return;
        }
        if(n==0){
            return;
        }
        char curChar=s.charAt(startIndex);
        if(curChar=='0'){
            if(!"".equals(tempS)){
                tempS+=".";
            }
            tempS+=curChar;
            restoreIpAddressesDFS(startIndex+1,s,n-1,tempS);
        }else{
            if(!"".equals(tempS)){
                tempS+=".";
            }
            for(int i=1;i<4;i++){
                if(startIndex+i>s.length()){
                    return;
                }
                String curStr=s.substring(startIndex,startIndex+i);
                if(Integer.valueOf(curStr)>255){
                    return;
                }
                restoreIpAddressesDFS(startIndex+i,s,n-1,tempS+curStr);
            }

        }

    }

}

子集【回溯算法】

👉 【LeetCode 直通车】:78 子集(中等)[62]

题解

class Solution {
    List<List<Integer>> result=new ArrayList<List<Integer>>();
    public List<List<Integer>> subsets(int[] nums) {
        if(nums==null||nums.length==0){
            return new ArrayList<List<Integer>>();
        }
        subsetsDFS(nums,0,new ArrayList<Integer>());
        return result;
    }
    public void subsetsDFS(int []nums,int start,List<Integer> tempList){
        result.add(new ArrayList(tempList));
        for(int i=start;i<nums.length;i++){
            int curNum=nums[i];
            tempList.add(curNum);
            subsetsDFS(nums,i+1,tempList);
            tempList.remove(tempList.size()-1);
        }
    }
}

文末福利

推荐一个非常有帮助的刷算法题的网址,labuladong 的算法小抄[63],通过套路,认准高频题目,直通大厂;这本小炒目前已经出版成书,对应的 Github 仓库[64]也有 86.2K Star,而且作者还在频繁更新,非常值得学习!

❤️谢谢

往期精文

  • 字节跳动最爱考的前端面试题:JavaScript 基础[65]  2696 👍

  • 字节跳动最爱考的前端面试题:CSS 基础[66] 687 👍

  • 字节跳动最爱考的前端面试题:计算机网络基础[67] 761 👍

欢迎关注公众号:图雀社区。 如果你想从零开始以实战的方式学习一门技术,亦或是想动手做一个比较完整的项目以准备面试,相信 「图雀社区」 的内容都能够帮助到你,成为初入前端的你成长路上的指南针。

原创不易

喜欢的话原创不易,给点鼓励吧 ❤️ 别忘了 分享、点赞、在看 三连哦~。

参考资料

[1]

【LeetCode 直通车】:234 回文链表(简单): https://leetcode-cn.com/problems/palindrome-linked-list/

[2]

【LeetCode 直通车】:206 反转链表(简单): https://leetcode-cn.com/problems/reverse-linked-list/

[3]

【LeetCode 直通车】:23 合并K个升序链表(困难): https://leetcode-cn.com/problems/merge-k-sorted-lists/

[4]

【LeetCode 直通车】:25 K 个一组翻转链表(困难): https://leetcode-cn.com/problems/reverse-nodes-in-k-group/

[5]

【LeetCode 直通车】:141 环形链表(简单): https://leetcode-cn.com/problems/linked-list-cycle/

[6]

【LeetCode 直通车】:148 排序链表(中等): https://leetcode-cn.com/problems/sort-list/

[7]

【LeetCode 直通车】:160 相交链表(简单): https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

[8]

【LeetCode 直通车】:5 最长回文子串(中等): https://leetcode-cn.com/problems/longest-palindromic-substring/

[9]

【LeetCode 直通车】:14 最长公共前缀(简单): https://leetcode-cn.com/problems/longest-common-prefix/

[10]

【LeetCode 直通车】:3 无重复字符的最长子串(中等): https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

[11]

【LeetCode 直通车】:76 最小覆盖子串(困难): https://leetcode-cn.com/problems/minimum-window-substring/

[12]

【LeetCode 直通车】:354 俄罗斯套娃信封问题(困难): https://leetcode-cn.com/problems/russian-doll-envelopes/

[13]

【LeetCode 直通车】:674 最长连续递增序列(简单): https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/

[14]

【LeetCode 直通车】:128 最长连续序列(困难): https://leetcode-cn.com/problems/longest-consecutive-sequence/

[15]

【LeetCode 直通车】:11 盛最多水的容器(中等): https://leetcode-cn.com/problems/container-with-most-water/

[16]

【LeetCode 直通车】:4 寻找两个正序数组的中位数(困难): https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

[17]

【LeetCode 直通车】:26 删除有序数组中的重复项(简单): https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/

[18]

【LeetCode 直通车】:695 岛屿的最大面积(中等): https://leetcode-cn.com/problems/max-area-of-island/

[19]

【LeetCode 直通车】:560 和为K的子数组(中等): https://leetcode-cn.com/problems/subarray-sum-equals-k/

[20]

【LeetCode 直通车】:1 两数之和(简单): https://leetcode-cn.com/problems/two-sum/

[21]

【LeetCode 直通车】:167 两数之和 II - 输入有序数组(简单): https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/

[22]

【LeetCode 直通车】:15 三数之和(中等): https://leetcode-cn.com/problems/3sum/

[23]

【LeetCode 直通车】:18 四数之和(中等): https://leetcode-cn.com/problems/4sum/

[24]

【LeetCode 直通车】:42 接雨水(困难): https://leetcode-cn.com/problems/trapping-rain-water/

[25]

【LeetCode 直通车】:55 跳跃游戏(中等): https://leetcode-cn.com/problems/jump-game/

[26]

【LeetCode 直通车】:45 跳跃游戏 II(中等): https://leetcode-cn.com/problems/jump-game-ii/

[27]

【LeetCode 直通车】:236 二叉树的最近公共祖先(简单): https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/

[28]

【LeetCode 直通车】:700 二叉搜索树中的搜索(简单): https://leetcode-cn.com/problems/search-in-a-binary-search-tree/

[29]

【LeetCode 直通车】:450 删除二叉搜索树中的节点(中等): https://leetcode-cn.com/problems/delete-node-in-a-bst/

[30]

【LeetCode 直通车】:222 完全二叉树的节点个数(中等): https://leetcode-cn.com/problems/count-complete-tree-nodes/

[31]

【LeetCode 直通车】:103 二叉树的锯齿形层序遍历(中等): https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/

[32]

【LeetCode 直通车】:452 用最少数量的箭引爆气球(中等): https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/

[33]

【LeetCode 直通车】:56 合并区间(中等): https://leetcode-cn.com/problems/merge-intervals/

[34]

【LeetCode 直通车】:4 寻找两个正序数组的中位数(困难): https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

[35]

【LeetCode 直通车】:392 判断子序列(简单): https://leetcode-cn.com/problems/is-subsequence/

[36]

【LeetCode 直通车】:34 在排序数组中查找元素的第一个和最后一个位置(中等): https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

[37]

【LeetCode 直通车】:300 最长递增子序列(中等): https://leetcode-cn.com/problems/longest-increasing-subsequence/

[38]

【LeetCode 直通车】:322 零钱兑换(中等): https://leetcode-cn.com/problems/coin-change/

[39]

【LeetCode 直通车】:1143 最长公共子序列(中等): https://leetcode-cn.com/problems/longest-common-subsequence/

[40]

【LeetCode 直通车】:72 编辑距离(困难): https://leetcode-cn.com/problems/edit-distance/

[41]

【LeetCode 直通车】:516 最长回文子序列(中等): https://leetcode-cn.com/problems/longest-palindromic-subsequence/

[42]

【LeetCode 直通车】:53 最大子序和(简单): https://leetcode-cn.com/problems/maximum-subarray/

[43]

【LeetCode 直通车】:121 买卖股票的最佳时机(简单): https://leetcode-cn.com/problems/container-with-most-water/

[44]

【LeetCode 直通车】:122 买卖股票的最佳时机 II(简单): https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/

[45]

【LeetCode 直通车】:123 买卖股票的最佳时机 III(困难): https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/

[46]

【LeetCode 直通车】:188 买卖股票的最佳时机IV(困难): https://leetcode-cn.com/problems/container-with-most-water/

[47]

【LeetCode 直通车】:309 买卖股票的最佳时机含冷冻期(中等): https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/

[48]

【LeetCode 直通车】:714 买卖股票的最佳时机含手续费(中等): https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/

[49]

【LeetCode 直通车】:752 打开转盘锁(中等): https://leetcode-cn.com/problems/open-the-lock/

[50]

【LeetCode 直通车】:111 二叉树的最小深度(简单): https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/

[51]

【LeetCode 直通车】:155 最小栈(简单): https://leetcode-cn.com/problems/min-stack/submissions/

[52]

【LeetCode 直通车】:496 下一个更大元素 I(简单): https://leetcode-cn.com/problems/next-greater-element-i/

[53]

【LeetCode 直通车】:503 下一个更大元素 II(中等): https://leetcode-cn.com/problems/next-greater-element-ii/

[54]

【LeetCode 直通车】:20 有效的括号(中等): https://leetcode-cn.com/problems/valid-parentheses/

[55]

【LeetCode 直通车】:71 简化路径(中等): https://leetcode-cn.com/problems/simplify-path/

[56]

【LeetCode 直通车】:695 岛屿的最大面积(中等): https://leetcode-cn.com/problems/max-area-of-island/

[57]

【LeetCode 直通车】:100 相同的树(简单): https://leetcode-cn.com/problems/same-tree/

[58]

【LeetCode 直通车】:51 N皇后(困难): https://leetcode-cn.com/problems/n-queens/

[59]

【LeetCode 直通车】:46 全排列(中等): https://leetcode-cn.com/problems/permutations/

[60]

【LeetCode 直通车】:22 括号生成(中等): https://leetcode-cn.com/problems/generate-parentheses/

[61]

【LeetCode 直通车】:93 复原 IP 地址(中等): https://leetcode-cn.com/problems/restore-ip-addresses/

[62]

【LeetCode 直通车】:78 子集(中等): https://leetcode-cn.com/problems/subsets/

[63]

labuladong 的算法小抄: https://www.yuque.com/tuture/interview/labuladong:https

[64]

Github 仓库: https://github.com/labuladong/fucking-algorithm

[65]

字节跳动最爱考的前端面试题:JavaScript 基础: https://juejin.cn/post/6934500357091360781

[66]

字节跳动最爱考的前端面试题:CSS 基础: https://juejin.cn/post/6936913689115099143

[67]

字节跳动最爱考的前端面试题:计算机网络基础: https://juejin.cn/post/6939691851746279437

 

前端技术优选

前端技术优选

为你精选前端领域优质技术博文,欢迎关注。

61篇原创内容

公众号

 
  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值