文章目录
1. 每日温度【高频】
739. 每日温度 2022.7.27
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] res = new int[temperatures.length];
Stack<Integer> sk = new Stack<>(); //单调栈
for (int i = temperatures.length - 1; i >= 0; i--) {
while (!sk.isEmpty() && temperatures[sk.peek()] <= temperatures[i]) {
sk.pop();
}
res[i] = sk.isEmpty() ? 0 : sk.peek() - i;
sk.push(i);
}
return res;
}
}
2. N数之和
15. 三数之和 2022.7.27
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
return nSum(nums, 3, 0, 0);
}
List<List<Integer>> nSum(int[] nums, int n, int start, int target) {
List<List<Integer>> res = new LinkedList<>();
if (n < 2 || nums.length < n) {
return res;
}
if (n == 2) {
int l = start, r = nums.length - 1;
while (l < r) {
int left = nums[l], right = nums[r];
int sum = left + right;
if (sum > target) {
r--;
}
if (sum < target) {
l++;
}
if (sum == target) {
res.add(Arrays.asList(left, right)); // Arrays.asList()
while (l < r && nums[l] == left) { // 剪枝
l++;
}
while (l < r && nums[r] == right) {
r--;
}
}
}
}
if (n > 2) {
for (int i = start; i < nums.length; i++) {
List<List<Integer>> tuples = nSum(nums, n - 1, i + 1, target - nums[i]);
for (List<Integer> tuple : tuples) {
List<Integer> t = new LinkedList<>(tuple); // 注意实例化
t.add(nums[i]);
res.add(t);
}
while (i < nums.length - 1 && nums[i] == nums[i + 1]) {
i++;
}
}
}
return res;
}
}
3. 复原 IP 地址
93. 复原 IP 地址 2022.8.5
class Solution {
static final int SEG_COUNT = 4;
List<String> ans = new ArrayList<String>();
int[] segments = new int[SEG_COUNT];
public List<String> restoreIpAddresses(String s) {
dfs(s, 0, 0);
return ans;
}
public void dfs(String s, int segId, int segStart) {
// 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
if (segId == SEG_COUNT) {
if (segStart == s.length()) {
StringBuffer ipAddr = new StringBuffer();
for (int i = 0; i < SEG_COUNT; i++) {
ipAddr.append(segments[i]);
if (i != SEG_COUNT - 1) {
ipAddr.append('.');
}
}
ans.add(ipAddr.toString());
}
return;
}
// 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
if (segStart == s.length()) {
return;
}
// 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
if (s.charAt(segStart) == '0') {
segments[segId] = 0;
dfs(s, segId + 1, segStart + 1);
}
// 一般情况,枚举每一种可能性并递归
int addr = 0;
for (int segEnd = segStart; segEnd < s.length(); segEnd++) {
addr = addr * 10 + (s.charAt(segEnd) - '0');
if (addr > 0 && addr <= 0xFF) {
segments[segId] = addr;
dfs(s, segId + 1, segEnd + 1);
} else {
break;
}
}
}
}
4. 简化路径【华子】
71. 简化路径 2022.7.27
class Solution {
public String simplifyPath(String path) {
String[] parts = path.split("/");
Stack<String> stk = new Stack<>();
// 借助栈计算最终的文件夹路径
for (String part : parts) {
if (part.isEmpty() || part.equals(".")) {
continue;
}
if (part.equals("..")) {
if (!stk.isEmpty()) stk.pop();
continue;
}
stk.push(part);
}
// 栈中存储的文件夹组成路径
String res = "";
while (!stk.isEmpty()) {
res = "/" + stk.pop() + res;
}
return res.isEmpty() ? "/" : res;
}
}
5. 接雨水
42. 接雨水 2022.8.5
class Solution {
public int trap(int[] height) {
int left = 0, right = height.length - 1;
int left_max = 0, right_max = 0;
int res = 0;
while (left < right) {
left_max = Math.max(left_max, height[left]);
right_max = Math.max(right_max, height[right]);
if (left_max < right_max) {
res += left_max - height[left];
left++;
} else {
res += right_max - height[right];
right--;
}
}
return res;
}
}
6. 轮转数组
189. 轮转数组 2022.8.5
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k %= n;
reverse(nums, 0, n - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, n - 1);
}
private void reverse(int[] nums, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
}
}
7. 重排链表
143. 重排链表 2022.8.6
class Solution {
public void reorderList(ListNode head) {
Deque<ListNode> dq = new LinkedList<>();
ListNode cur = head;
while (cur != null) {
dq.addLast(cur);
cur = cur.next;
}
while (!dq.isEmpty()) {
if (cur == null) {
cur = dq.pollFirst();
} else {
cur.next = dq.pollFirst();
cur = cur.next;
}
cur.next = dq.pollLast();
cur = cur.next;
}
if (cur != null) {
cur.next = null;
}
}
}
8. 只出现一次的数字
136. 只出现一次的数字 2022.8.6
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for (int n : nums) {
res ^= n;
}
return res;
}
}
9. 最长回文子串
5. 最长回文子串 2022.8.7
class Solution {
public String longestPalindrome(String s) {
String res = "";
for (int i = 0; i < s.length(); i++) {
String String1 = palindrom(s, i, i + 1);
String String2 = palindrom(s, i, i);
res = res.length() > String1.length() ? res : String1;
res = res.length() >String2.length() ? res : String2;
}
return res;
}
String palindrom(String s, int start, int end) {
while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) {
start--;
end++;
}
return s.substring(start + 1, end);
}
}
10. 回文链表
234. 回文链表 2022.8.7
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
slow = slow.next;
}
ListNode newNode = reverse(slow);
while (newNode != null) {
if (newNode.val != head.val) {
return false;
}
newNode = newNode.next;
head = head.next;
}
return true;
}
ListNode reverse(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode last = reverse(head.next);
head.next.next = head;
head.next = null;
return last;
}
}
11. 相交链表
160. 相交链表 2022.8.7
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode a = headA, b = headB;
while (a != b) {
if (a == null) {
a = headB;
} else {
a = a.next;
}
if (b == null) {
b = headA;
} else {
b = b.next;
}
}
return a;
}
}
12. 数组中的第 K 个最大元素(中等)
215. 数组中的第K个最大元素 2022.8.7
方法一:二叉堆(优先队列)【推荐】
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
for (int e : nums) {
pq.offer(e);
if (pq.size() > k) {
pq.poll();
}
}
return pq.peek();
}
}
方法二:快排
class Solution {
public int findKthLargest(int[] nums, int k) {
shuffle(nums);
int lo = 0, hi = nums.length - 1;
k = nums.length - k;
while (lo <= hi) {
int p = partition(nums, lo, hi);
if (p < k) {
lo = p + 1;
} else if (p > k) {
hi = p - 1;
} else {
return nums[p];
}
}
return -1;
}
// void sort(int[] nums, int lo, int hi) {
// if (lo >= hi) {
// return;
// }
// int p = partition(nums, lo, hi);
// sort(nums, lo, p - 1);
// sort(nums, p + 1, hi);
// }
int partition(int[] nums, int lo, int hi) {
int pivot = nums[lo];
int i = lo + 1, j = hi;
while (i <= j) {
while (j > lo && nums[j] > pivot) {
j--;
}
while (i < hi && nums[i] <= pivot) {
i++;
}
if (i >= j) {
break;
}
swap(nums, i, j);
}
swap(nums, lo, j);
return j;
}
void shuffle(int[] nums) {
Random rand = new Random();
int n = nums.length;
for (int i = 0; i < n; i++) {
swap(nums, i, i + rand.nextInt(n - i));
}
}
void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
13. K 个一组翻转链表
25. K 个一组翻转链表 2022.8.7
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
// 新建两个结点
ListNode a = head, b = head;
for (int i = 0; i < k; i++) {
if (b == null) {
return a;
}
b = b.next;
}
ListNode newNode = reverse(a, b);
a.next = reverseKGroup(b, k);
return newNode;
}
ListNode reverse(ListNode a, ListNode b) {
ListNode pre = null, cur = a, nxt = a;
// 循环条件记得改为 b
while (cur != b) {
nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
}
14. 不同路径
62. 不同路径 2022.8.8
class Solution {
int[][] memo = null;
public int uniquePaths(int m, int n) {
memo = new int[m][n];
return dp(m - 1, n - 1);
}
int dp(int i, int j) {
if (i == 0 || j == 0) {
return 1;
}
if (memo[i][j] != 0) {
return memo[i][j];
}
memo[i][j] = dp(i - 1, j) + dp(i, j - 1);
return memo[i][j];
}
}
15. 零钱兑换
322. 零钱兑换 2022.8.8
public class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
// 这里我们还得给dp[i]赋予一个尽量大的初始值
for(int i = 0; i <= amount; i++) {
dp[i] = amount + 1;
}
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
// 计算机 dp[i] 所需要的最少硬币数量
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
16. LRU 缓存
146. LRU 缓存 2022.8.8
class LRUCache {
int cap;
LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
public LRUCache(int capacity) {
this.cap = capacity;
}
public int get(int key) {
if (!cache.containsKey(key)) {
return -1;
}
// 将 key 变为最近使用
makeRecently(key);
return cache.get(key);
}
public void put(int key, int val) {
if (cache.containsKey(key)) {
// 修改 key 的值
cache.put(key, val);
// 将 key 变为最近使用
makeRecently(key);
return;
}
if (cache.size() >= this.cap) {
// 链表头部就是最久未使用的 key
int oldestKey = cache.keySet().iterator().next();
cache.remove(oldestKey);
}
// 将新的 key 添加链表尾部
cache.put(key, val);
}
private void makeRecently(int key) {
int val = cache.get(key);
// 删除 key,重新插入到队尾
cache.remove(key);
cache.put(key, val);
}
}
// 详细解析参见:
// https://labuladong.github.io/article/?qno=146
17. 打家劫舍
class Solution {
public int rob(int[] nums) {
if(nums.length == 0)
return 0;
int [] dp = new int[nums.length];
dp[0] = nums[0];
// 每次做数组判定时都需要做数组边界判定,防止越界
if(nums.length < 2)
return nums[0];
dp[1] = (nums[0]>nums[1]) ? nums[0] : nums[1];
for(int i = 2; i<nums.length; i++)
dp[i] = ((nums[i] + dp[i-2]) > dp[i-1]) ? (nums[i]+dp[i-2]) : dp[i-1];
return dp[nums.length-1];
}
}
18. 二叉树的右视图
class Solution {
List<Integer> res = new ArrayList<>();
// 记录递归的层数
int depth = 0;
public List<Integer> rightSideView(TreeNode root) {
traverse(root);
return res;
}
// 二叉树遍历函数
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序遍历位置
depth++;
if (res.size() < depth) {
// 这一层还没有记录值
// 说明 root 就是右侧视图的第一个节点
res.add(root.val);
}
// 注意,这里反过来,先遍历右子树再遍历左子树
// 这样首先遍历的一定是右侧节点
traverse(root.right);
traverse(root.left);
// 后序遍历位置
depth--;
}
}
19. 二叉树的完全性检验
class Solution {
public boolean isCompleteTree(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// 遍历完所有非空节点时变成 true
boolean end = false;
// while 循环控制从上向下一层层遍历
while (!q.isEmpty()) {
int sz = q.size();
// for 循环控制每一层从左向右遍历
for (int i = 0; i < sz; i++) {
TreeNode cur = q.poll();
if (cur == null) {
// 第一次遇到 null 时 end 变成 true
// 如果之后的所有节点都是 null,则说明是完全二叉树
end = true;
} else {
if (end) {
// end 为 true 时遇到非空节点说明不是完全二叉树
return false;
}
// 将下一层节点放入队列,不用判断是否非空
q.offer(cur.left);
q.offer(cur.right);
}
}
}
return true;
}
}
20. 航班预订统计【华子】
1109. 航班预订统计 2022.8.10
写法一:
// 差分数组
class Solution {
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] res = new int[n];
Difference df = new Difference(res);
for (int[] booking : bookings) {
int i = booking[0] - 1;
int j = booking[1] - 1;
int val = booking[2];
df.increment(i, j, val);
}
return df.result();
}
class Difference {
private int[] diff;
public Difference(int[] nums) {
assert nums.length > 0;
diff = new int[nums.length];
diff[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
diff[i] = nums[i] - nums[i - 1];
}
}
public void increment(int i, int j, int val) {
diff[i] += val;
if (j + 1 < diff.length) {
diff[j + 1] -= val;
}
}
public int[] result() {
int[] res = new int[diff.length];
res[0] = diff[0];
for (int i = 1; i < diff.length; i++) {
res[i] = res[i - 1] + diff[i];
}
return res;
}
}
}
写法二:
class Solution {
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] res = new int[n];
int[] diff = new int[n];
for (int[] booking : bookings) {
int i = booking[0] - 1;
int j = booking[1] - 1;
int val = booking[2];
for (int k = i; k <= j; k++) {
diff[k] += val;
}
}
return diff;
}
写法三:
class Solution {
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] res = new int[n];
int[] diff = new int[n];
for (int[] booking : bookings) {
int i = booking[0] - 1;
int j = booking[1] - 1;
int val = booking[2];
diff[i] += val;
if (j + 1 < n) {
diff[j + 1] -= val;
}
}
res[0] = diff[0];
for (int i = 1; i < n; i++) {
res[i] = res[i - 1] + diff[i];
}
return res;
}