LeetCode刷题 - 经典考题小结

一.TopK

常见解法:heap(max,min),quickSelect,bucket sort

follow up:

1.k,n - k优化

2.重复数据很多怎么办

3.online/offline algorithm?online = stream

4.query次数特别多,不同k值

5.大数据无法放入内存处理

6.系统设计无限扩展

二.Jump Game

Jump game1:DP 或者 Greedy

Jump game2:DP 或者 Greedy

Jump game3:BFS 或者 DFS

Jump game4:单向BFS 或者 双向BFS

Jump game5:DP

Jump game6:Sliding window + PQ 或者 Sliding window + 单调队列

Jump game7:DP 或者 单调队列

Frog jump:DP 或者 更优化的剪枝DP

其中 dfs + memo 的 dp 最好想到实现,最难的是单调队列

注意判断不同的选择和题目起点终点的要求

三.Parentheses 括号

1.Rolling state的思路,类似扫描线数飞机,我们遇到左括号 +1,右括号 -1,来判断是否平衡。中间任意时候平衡被破坏都invalid

ps:由于括号的特殊性,不同类型或者找invalid的括号index的时候,需要用到stack来辅助保存当下的状态

stack可以用来保存:①不同类型括号 ②括号index ③前一层的数字和

2.backtracking类似subset,生成括号

四.Majority Number

什么是摩尔投票法?Boyer-Moore Voting

该算法时间复杂度为O(n),空间复杂度为O(1)。只需要对原数组进行两趟扫描,并且简单易实现。第一趟扫描我们得到一个候选节点candidate,第二趟扫描我们判断candidate出现的次数是否大于n/2

第一趟扫描中,我们需要记录2个值:

1.candidate,初值可以为任何数

2.count,初值为0

之后,对于数组中的每一个元素,首先判断count是否为0,若为0,则把candidate设置为当前元素,之后判断candidate是否与当前元素相等,若相等则count += 1,否则count -= 1

python代码:

candidate = 0
count = 0
for value in input:
  if count == 0:
    candidate = value
  if candidate == value:
    count += 1
  else:
    count -= 1

在第一趟扫描结束后,如果数组中存在多数元素,那么candidate即为其值,如果原数组不存在多数元素,则candidate的值没有意义。所以需要第二趟扫描来统计candidate出现的次数来判断其是否为多数元素

总结

1.遇到目标count++,不是目标count--,count为0替换当前目标

2.记得最后对最后剩下的目标全局再次计数以确保K众数存在

3.对于大数据统计可以parallel优化

五.Two Sum

最高频的是 2 sum,O(n)最快hashmap

2 sum bst 相关考虑iterator可以节省空间

3 sum系列,要用到two pointer双指针

4 sum系列,开始和 k sum类似,如果只问count,可以考虑简化为2 sum或者用dp背包来数数

k sum,如果是问具体内部取了哪些数字,我们就用backtracking去展开所有的组合,暴力2^N*k去做;用recursive去ksum变成(k-1)sum,一直到剩下最后的2个数字用2sum,最后时间复杂度为N^(k-1)次一般更快当k小N大的时候

two pointer:时间慢一些,便于去重,找相近答案。可以集合iterator处理树类

hashmap/set:只可以找确定的target,速度快,不便于去重

六.Palindrome回文

回文数是指正序(从左到右)和倒序(从右到左)读都是一样的数字integer,字符串string,或者字符序列subsequence

注意回文数可以长度为奇数或者偶数,单个字符也是回文

回文知识点:DP,中心扩散,暴力,greedy,backtracking (math,kmp,rolling hash)

总结

1.palindrome一般可以双指针,或者reverse来做比较

2.palindrome substring一般可以DP或者中心扩散法,马拉车不要求。DP的时候如果选择右上三角形,只和左下角的前一个状态有关,因为palindrome一次比较边上两个character

3.palindrome subsequence,熟悉LCS可以直接用LCS,不用LCS也可以直接DP,和左下(match),左,下(not match)相关

4.backtracking的话直接按照模板写,可以DP做预先优化来判断substring(i,j) 是否为palindrome

模板

1.中心扩散法

private boolean isPalindrome(String s) {
  int left = 0, right = s.length() - 1;
  while (left < right) {
    if (s.charAt(left) == s.charAt(right)) {
      left++;
      right--;
    } else {
      return false;
    }
  }
  return true;
}

2.常规DP

public String longestPalindrome(String s) {
  int N = s.length();
  boolean[][] dp = new boolean[N][N];
  int start = 0, end = 0;
  for (int i = N - 1; i >= 0; i--)
    for (int j = i; j < N; j++)
      if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) {
        if (end - start < j - i) {
          start = i;
          end = j;
        }
        dp[i][j] = true;
      }
  return s.substring(start, end + 1);
}

七.买卖股票

State machine(状态机)

选择有:buy,sell,(rest)

状态有:当前天数 i

目前为止最多交易次数 k

当前的持有状态:1表示持有,0表示没有持有

题目要求cool down我们买的时候可以根据前天 i - 2 的状态来保持冷却日

这个问题的状态有三个:

1.天数(到第几天的时候)

2.允许交易的最大次数

3.当前的持有状态(即rest的状态,我们不妨用1表示持有,0表示没有持有)

八.calculator

1.用栈来处理 + - * /

2.用递归来处理 '(',')'

3.Java可以用 Character.isDigit() 或者 '0' <= char <= '9'来检查是否是一个数字

4.建议同时使用stack和递归

int i = 0;
public int calculator(String s) {
  Stack<Integer> stack = new Stack<>();
  char operator = '+';
  int num = 0;
  while (i < s.length()) {
    char c = s.charAt(i++);
    if (Character.isDigit(c)) num = num * 10 + (c - '0');
    if (c == '(') num = calculate(s);
    if (i >= s.length() || c == '+' || c == '-' || c == '*' || c == '/' || c == ')') {
      if (operator == '+') stack.push(-num);
      else if (operator == '-') stack.push(stack.pop() * num);
      else if (operator == '*') stack.push(stack.pop() / num);
      operator = c;
      num = 0;
    }
    if (c == ')') break;
  }
}

如果想将空间压缩成 O(1)

class Solution {
  int i = -1;
  public int calculate(String s) {
    int ans = 0,bef = 0;
    char op = '+';
    int num = 0;
    while (i < s.length() - 1) {
      char ch = s.charAt(++i);
      if (ch == '(') num = calculate(s);
      if (cha >= '0' && ch <= '9') num = num * 10 + (ch - '0');
      if (i == s.length() - 1 || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == ')') {
        if (op == '+') {
          ans += bef;
          bef = num;
        } else if (op == '-') {
          ans += bef;
          bef =- num;
        } else if (op == '*') {
          bef *= num;
        } else {
          bef /= num;
        }
        op = ch;
        num = 0;
      }
      if (ch == ')') break;
    }
    if (ch == ')') break;
  }
  return ans + bef;
}

九.number of island

考察的知识点

1.DFS

2.BFS

3,Union Find

4.Path to describe shape

5.Tarjan's Algorithm

6.Distributed processing as a follow up

总结

1.DFS,BFS,Union Find必须熟悉,stack和queue

2.Trajan's考到的概率极低

void dfs(int[][] grid, int r, int c) {
  //判断 base case
  if (!inArea(grid, r, c)) {
    return;
  }
  //如果这个格子不是岛屿,直接返回
  if (grid[r][c] != 1) {
    return;
  }
  grid[r][c] = 2; //将格子标记为'已遍历过'

  //访问上,下,左,右四个相邻节点
  dfs(grid, r-1, c);
  dfs(grid, r+1, c);
  dfs(grid, r, c-1);
  dfs(grid, r, c+1);
}

//判断坐标(r,c)是否在网格中
boolean inArea(int[][] grid, int r, int c) {
  return 0 <= r && r < grid.length && 0 <= c && c < grid[0].length;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值