LeetCode 热题 Hot 100
- 231. 2 的幂
// 位运算 n&(n-1) 在算法中挺常见的,作用是消除数字 n 的二进制表示中的最后一个 1,用这个技巧可以判断 2 的指数。
class Solution {
public boolean isPowerOfTwo(int n) {
if (n <= 0) return false;
return (n & (n - 1)) == 0;
}
}
- 338. 比特位计数
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n + 1];
Arrays.fill(dp, 0);
dp[0] = 0;
for (int i = 1; i < n + 1; i++) {
// 位运算 n&(n-1) 在算法中挺常见的,作用是消除数字 n 的二进制表示中的最后一个 1
// dp[i] 肯定是比 dp[i & (i - 1)] 多一个1,累加上来就行
dp[i] = dp[i & (i - 1)] + 1;
}
return dp;
}
}
- 347. 前 K 个高频元素
class Solution {
/**
* 最小堆
*/
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> freq = new HashMap<>();
for (int num : nums) {
int f = freq.getOrDefault(num, 0) + 1;
freq.put(num, f);
}
// 比较出现频率
PriorityQueue<Integer> minHeap = new PriorityQueue<>((o1, o2) -> freq.get(o1) - freq.get(o2));
int[] res = new int[k];
for (Integer elem : freq.keySet()) {
minHeap.add(elem);
if (minHeap.size() > k) {
// 移除最小的那个
minHeap.remove();
}
}
for (int i = 0; i < k; i++) {
res[i] = minHeap.remove();
}
return res;
}
}
- 394. 字符串解码
class Solution {
/**
* 4种情况
* 1: 数字
* 2: 字母
* 3: [
* 4: ]
*/
public String decodeString(String s) {
// 乘积栈
Stack<Integer> times = new Stack<>();
Stack<String> preStrs = new Stack<>();
String res = "";
int time = 0;
for (char c : s.toCharArray()) {
if (isNum(c)) {
time = time * 10 + Integer.parseInt(c + "");
} else if (c == '[') {
times.push(time);
preStrs.push(res);
time = 0;
res = "";
} else if (c == ']') {
int curTime = times.pop();
StringBuilder preStr = new StringBuilder(preStrs.pop());
while (curTime > 0) {
preStr.append(res);
curTime--;
}
res = preStr.toString();
} else {
res += c;
}
}
return res;
}
private boolean isNum(char c) {
return c >= '0' && c <= '9';
}
}
- 399. 除法求值
暂时不写
- 406. 根据身高重建队列
class Solution {
public int[][] reconstructQueue(int[][] people) {
/**
* 分析题意:身高较高的同学先进行插入操作,然后身高矮的同学按照k的值为索引,插入到编号为k的位置上
* 他前面肯定有k个高个子比他高或相等
* 规则: 先按身高h降序排列,然后按照比高个数k升序排列
* 等排序遍历一趟之后,还有人没有落在最终的位置,我们就按照他的k值作为索引将其插入到k位置上
*/
// 原数组[[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
// 先排序一遍
// [[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
// 接着按照k值一个个插入
// [7,0]
// [7,0],[7,1]
// [7,0],[6,1],[7,1]
// [5,0],[7,0],[6,1],[7,1]
// [5,0],[7,0],[5,2],[6,1],[7,1]
// [5,0],[7,0],[5,2],[6,1],[4,4],[7,1]
// 如果身高相等,我们就按照k升序排列,否则按照h降序排列
Arrays.sort(people, (o1, o2) -> o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0]);
System.out.println(Arrays.deepToString(people));
List<int[]> queue = new ArrayList<>();
for (int[] person : people) {
queue.add(person[1], person);
}
return queue.toArray(new int[0][]);
}
}
- 416. 分割等和子集
class Solution {
/**
* 对于这个问题,我们可以先对集合求和,得出 sum,然后把问题转化为背包问题:
* 给一个可装载重量为 sum / 2 的背包和 N 个物品,每个物品的重量为 nums[i]。现在让你装物品,是否存在一种装法,能够恰好将背包装满?
* 第一步要明确两点,「状态」和「选择」,状态就是「背包的容量」和「可选择的物品」,选择就是「装进背包」或者「不装进背包」。
* dp 数组的定义:dp[i][j] = x 表示,对于前 i 个物品,
* 当前背包的容量为 j 时,若 x 为 true,则说明可以恰好将背包装满,若 x 为 false,则说明不能恰好将背包装满。
* 根据 dp 数组含义,可以根据「选择」对 dp[i][j] 得到以下状态转移:
* 如果不把 nums[i] 算入子集,或者说你不把这第 i 个物品装入背包,那么是否能够恰好装满背包,取决于上一个状态 dp[i-1][j],继承之前的结果。
* 如果把 nums[i] 算入子集,或者说你把这第 i 个物品装入了背包,那么是否能够恰好装满背包,取决于状态 dp[i-1][j-nums[i-1]]。
*/
public boolean canPartition(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
// 和为奇数时,不可能划分成两个和相等的集合
if (sum % 2 != 0) return false;
sum /= 2;
int n = nums.length;
boolean[][] dp = new boolean[n + 1][sum + 1];
for (int i = 0; i <= n; i++) {
dp[i][0] = true;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= sum; j++) {
if (j - nums[i - 1] < 0) {
// 背包容量不足,不能装入第 i 个物品
dp[i][j] = dp[i - 1][j];
} else {
// 装入或不装入背包
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];
}
}
}
return dp[n][sum];
}
}
- 37. 路径总和
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false;
if (root.left == null && root.right == null) return targetSum == root.val;
return hasPathSum(root.left, targetSum - root.val)
||
hasPathSum(root.right, targetSum - root.val);
}
}
- 37. 路径总和 II
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<List<Integer>> pathList = new LinkedList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if (root == null) return pathList;
backtack(root, targetSum);
return pathList;
}
private void backtack(TreeNode root, int targetSum) {
if (root == null) return;
int remain = targetSum - root.val;
if (root.left == null && root.right == null) {
if (remain == 0) {
// 找到一条路径
path.addLast(root.val);
pathList.add(new LinkedList<>(path));
path.removeLast();
}
return;
}
// 维护路径列表
path.addLast(root.val);
backtack(root.left, remain);
path.removeLast();
path.addLast(root.val);
backtack(root.right, remain);
path.removeLast();
}
}
- 37. 路径总和 III
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 记录前缀和
// 定义:从二叉树的根节点开始,路径和为 pathSum 的路径有 preSumCount.get(pathSum) 个
Map<Integer, Integer> preSumCount;
int res = 0;
int targetSum;
public int pathSum(TreeNode root, int targetSum) {
this.targetSum = targetSum;
preSumCount = new HashMap<>();
preSumCount.put(0, 1);
backtrack(0, root);
return res;
}
private void backtrack(int sum, TreeNode root) {
if (root == null) return;
sum += root.val;
if (preSumCount.containsKey(sum - targetSum) && preSumCount.get(sum - targetSum) >= 1) {
res += preSumCount.get(sum - targetSum);
}
preSumCount.put(sum, preSumCount.getOrDefault(sum, 0) + 1);
backtrack(sum, root.left);
backtrack(sum, root.right);
preSumCount.put(sum, preSumCount.get(sum) - 1);
}
}