LeetCode 高频 50 题:最优解笔记
题目描述: 给定整数数组 nums 和目标值 target,在数组中找出和为目标值的两个整数,返回它们的索引。 示例: 输入:nums = [2,7,11,15], target = 9 输出:[0,1] 最优解思路: 使用哈希表存储元素值到索引的映射。遍历数组,对于每个元素 num,检查 target - num 是否在哈希表中。若存在则返回结果,否则将当前元素加入哈希表。 时间复杂度:O(n) 空间复杂度:O(n)
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
num_map = {}
for i, num in enumerate(nums):
complement = target - num
if complement in num_map:
return [num_map[complement], i]
num_map[num] = i
return []class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[]{map.get(complement), i};
}
map.put(nums[i], i);
}
return new int[0];
}
}class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (map.find(complement) != map.end()) {
return {map[complement], i};
}
map[nums[i]] = i;
}
return {};
}
};题目描述: 反转一个单链表。 示例: 输入:1→2→3→4→5→NULL 输出:5→4→3→2→1→NULL 最优解思路: 使用三个指针:prev(前驱)、curr(当前)、next(后继)。遍历链表,将 curr.next 指向 prev,然后更新三个指针位置。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
prev, curr = None, head
while curr:
next_temp = curr.next
curr.next = prev
prev = curr
curr = next_temp
return prevclass Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
}class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* nextTemp = curr->next;
curr->next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
};题目描述: 给定只包含括号字符的字符串,判断括号是否有效。 示例: 输入:s = “()[]{}” 输出:true 最优解思路: 使用栈存储左括号。遍历字符串,遇到左括号入栈,遇到右括号则检查栈顶是否匹配。最后检查栈是否为空。 时间复杂度:O(n) 空间复杂度:O(n)
class Solution:
def isValid(self, s: str) -> bool:
stack = []
mapping = {")": "(", "}": "{", "]": "["}
for char in s:
if char in mapping:
top_element = stack.pop() if stack else '#'
if mapping[char] != top_element:
return False
else:
stack.append(char)
return not stackclass Solution {
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
Map<Character, Character> map = Map.of(')', '(', '}', '{', ']', '[');
for (char c : s.toCharArray()) {
if (map.containsKey(c)) {
if (stack.isEmpty() || stack.pop() != map.get(c)) return false;
} else {
stack.push(c);
}
}
return stack.isEmpty();
}
}class Solution {
public:
bool isValid(string s) {
stack<char> st;
unordered_map<char, char> map = {{')', '('}, {']', '['}, {'}', '{'}};
for (char c : s) {
if (map.count(c)) {
if (st.empty() || st.top() != map[c]) return false;
st.pop();
} else {
st.push(c);
}
}
return st.empty();
}
};题目描述: 给定股票价格数组,计算一次交易的最大利润。 示例: 输入:[7,1,5,3,6,4] 输出:5(1买6卖) 最优解思路: 遍历价格数组,维护历史最低价 min_price 和最大利润 max_profit。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def maxProfit(self, prices: List[int]) -> int:
min_price = float('inf')
max_profit = 0
for price in prices:
min_price = min(min_price, price)
max_profit = max(max_profit, price - min_price)
return max_profitclass Solution {
public int maxProfit(int[] prices) {
int minPrice = Integer.MAX_VALUE;
int maxProfit = 0;
for (int price : prices) {
minPrice = Math.min(minPrice, price);
maxProfit = Math.max(maxProfit, price - minPrice);
}
return maxProfit;
}
}class Solution {
public:
int maxProfit(vector<int>& prices) {
int minPrice = INT_MAX;
int maxProfit = 0;
for (int price : prices) {
minPrice = min(minPrice, price);
maxProfit = max(maxProfit, price - minPrice);
}
return maxProfit;
}
};题目描述: 返回二叉树节点值的层序遍历结果(逐层从左到右)。 示例: 输入:root = [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]] 最优解思路: 使用队列进行BFS。记录每层节点数,处理完一层后再处理下一层。 时间复杂度:O(n) 空间复杂度:O(n)
from collections import deque
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root: return []
result = []
queue = deque([root])
while queue:
level_size = len(queue)
current_level = []
for _ in range(level_size):
node = queue.popleft()
current_level.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
result.append(current_level)
return resultclass Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int levelSize = queue.size();
List<Integer> currentLevel = new ArrayList<>();
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
currentLevel.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(currentLevel);
}
return result;
}
}class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int levelSize = q.size();
vector<int> currentLevel;
for (int i = 0; i < levelSize; i++) {
TreeNode* node = q.front(); q.pop();
currentLevel.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
result.push_back(currentLevel);
}
return result;
}
};题目描述: 找出整数数组中具有最大和的连续子数组。 示例: 输入:[-2,1,-3,4,-1,2,1,-5,4] 输出:6(子数组[4,-1,2,1]) 最优解思路: Kadane算法:遍历数组,维护当前子数组和curr_sum和最大和max_sum。当curr_sum<0时重置为0。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
curr_sum = max_sum = nums[0]
for num in nums[1:]:
curr_sum = max(num, curr_sum + num)
max_sum = max(max_sum, curr_sum)
return max_sumclass Solution {
public int maxSubArray(int[] nums) {
int currSum = nums[0];
int maxSum = nums[0];
for (int i = 1; i < nums.length; i++) {
currSum = Math.max(nums[i], currSum + nums[i]);
maxSum = Math.max(maxSum, currSum);
}
return maxSum;
}
}class Solution {
public:
int maxSubArray(vector<int>& nums) {
int currSum = nums[0];
int maxSum = nums[0];
for (int i = 1; i < nums.size(); i++) {
currSum = max(nums[i], currSum + nums[i]);
maxSum = max(maxSum, currSum);
}
return maxSum;
}
};题目描述: 爬n阶楼梯,每次爬1或2阶,有多少种不同方法。 示例: 输入:3 输出:3 最优解思路: 动态规划:dp[i] = dp[i-1] + dp[i-2],使用滚动数组优化空间。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def climbStairs(self, n: int) -> int:
if n <= 2: return n
a, b = 1, 2
for _ in range(3, n+1):
a, b = b, a + b
return bclass Solution {
public int climbStairs(int n) {
if (n <= 2) return n;
int a = 1, b = 2;
for (int i = 3; i <= n; i++) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
}class Solution {
public:
int climbStairs(int n) {
if (n <= 2) return n;
int a = 1, b = 2;
for (int i = 3; i <= n; i++) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
};题目描述: 在数组中找到所有不重复的三元组,满足a+b+c=0。 示例: 输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 最优解思路: 排序+双指针:固定一个数,在剩余数组中使用双指针寻找两数之和。注意去重处理。 时间复杂度:O(n²) 空间复杂度:O(1)
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
result = []
n = len(nums)
for i in range(n-2):
if i > 0 and nums[i] == nums[i-1]:
continue
left, right = i+1, n-1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total < 0:
left += 1
elif total > 0:
right -= 1
else:
result.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left+1]:
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
left += 1
right -= 1
return resultclass Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> result = new ArrayList<>();
int n = nums.length;
for (int i = 0; i < n-2; i++) {
if (i > 0 && nums[i] == nums[i-1]) continue;
int left = i+1, right = n-1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum < 0) left++;
else if (sum > 0) right--;
else {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (left < right && nums[left] == nums[left+1]) left++;
while (left < right && nums[right] == nums[right-1]) right--;
left++; right--;
}
}
}
return result;
}
}class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> result;
int n = nums.size();
for (int i = 0; i < n-2; i++) {
if (i > 0 && nums[i] == nums[i-1]) continue;
int left = i+1, right = n-1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum < 0) left++;
else if (sum > 0) right--;
else {
result.push_back({nums[i], nums[left], nums[right]});
while (left < right && nums[left] == nums[left+1]) left++;
while (left < right && nums[right] == nums[right-1]) right--;
left++; right--;
}
}
}
return result;
}
};题目描述: 将两个升序链表合并为一个新的升序链表。 示例: 输入:1→2→4, 1→3→4 输出:1→1→2→3→4→4 最优解思路: 使用虚拟头节点,比较两个链表节点值,将较小节点连接到新链表。 时间复杂度:O(n+m) 空间复杂度:O(1)
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode()
curr = dummy
while l1 and l2:
if l1.val < l2.val:
curr.next = l1
l1 = l1.next
else:
curr.next = l2
l2 = l2.next
curr = curr.next
curr.next = l1 if l1 else l2
return dummy.nextclass Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode();
ListNode curr = dummy;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
curr.next = l1;
l1 = l1.next;
} else {
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
curr.next = l1 != null ? l1 : l2;
return dummy.next;
}
}class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode dummy;
ListNode* curr = &dummy;
while (l1 && l2) {
if (l1->val < l2->val) {
curr->next = l1;
l1 = l1->next;
} else {
curr->next = l2;
l2 = l2->next;
}
curr = curr->next;
}
curr->next = l1 ? l1 : l2;
return dummy.next;
}
};题目描述: 给定二叉树和两个节点,找到这两个节点的最近公共祖先。 示例: 输入:root = [3,5,1,6,2,0,8,null,null,7,4], p=5, q=1 输出:3 最优解思路: 递归遍历二叉树:若当前节点为p或q,返回当前节点;递归左右子树;根据左右子树返回结果判断LCA位置。 时间复杂度:O(n) 空间复杂度:O(h)
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right:
return root
return left or rightclass Solution {
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 && right != null) return root;
return left != null ? left : right;
}
}class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (!root || root == p || root == q) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left && right) return root;
return left ? left : right;
}
};题目描述: 在未排序数组中找到第K个最大元素。 示例: 输入:[3,2,1,5,6,4], k=2 输出:5 最优解思路: 快速选择算法(基于快速排序的划分思想)。每次划分后根据pivot位置调整搜索范围。 时间复杂度:平均O(n),最坏O(n²) 空间复杂度:O(1)
import random
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
def partition(left, right):
pivot_idx = random.randint(left, right)
nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx]
pivot = nums[right]
i = left
for j in range(left, right):
if nums[j] > pivot: # 找第K大所以用>
nums[i], nums[j] = nums[j], nums[i]
i += 1
nums[i], nums[right] = nums[right], nums[i]
return i
left, right = 0, len(nums)-1
k = k - 1 # 转换为0-based索引
while left <= right:
pos = partition(left, right)
if pos == k:
return nums[pos]
elif pos < k:
left = pos + 1
else:
right = pos - 1
return nums[left]import java.util.Random;
class Solution {
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length-1, nums.length-k);
}
private int quickSelect(int[] nums, int left, int right, int k) {
if (left == right) return nums[left];
Random rand = new Random();
int pivotIdx = left + rand.nextInt(right - left);
pivotIdx = partition(nums, left, right, pivotIdx);
if (k == pivotIdx) return nums[k];
else if (k < pivotIdx) return quickSelect(nums, left, pivotIdx-1, k);
else return quickSelect(nums, pivotIdx+1, right, k);
}
private int partition(int[] nums, int left, int right, int pivotIdx) {
int pivot = nums[pivotIdx];
swap(nums, pivotIdx, right);
int storeIdx = left;
for (int i = left; i <= right; i++) {
if (nums[i] < pivot) {
swap(nums, storeIdx, i);
storeIdx++;
}
}
swap(nums, storeIdx, right);
return storeIdx;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}#include <vector>
#include <cstdlib>
using namespace std;
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int left = 0, right = nums.size()-1;
k = nums.size() - k; // 转换为第k小
while (left <= right) {
int pivotIdx = partition(nums, left, right);
if (pivotIdx == k) return nums[pivotIdx];
else if (pivotIdx < k) left = pivotIdx + 1;
else right = pivotIdx - 1;
}
return nums[left];
}
private:
int partition(vector<int>& nums, int left, int right) {
int pivot = nums[right];
int i = left;
for (int j = left; j < right; j++) {
if (nums[j] < pivot) {
swap(nums[i], nums[j]);
i++;
}
}
swap(nums[i], nums[right]);
return i;
}
};题目描述: 给定整数数组,返回数组output,其中output[i]等于除nums[i]外其余元素的乘积。 示例: 输入:[1,2,3,4] 输出:[24,12,8,6] 最优解思路: 使用左右乘积列表。先从左到右计算左侧乘积,再从右到左计算右侧乘积并合并结果。 时间复杂度:O(n) 空间复杂度:O(1)(输出数组不计入空间复杂度)
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
result = [1] * n
# 计算左侧乘积
left_product = 1
for i in range(n):
result[i] = left_product
left_product *= nums[i]
# 计算右侧乘积并合并
right_product = 1
for i in range(n-1, -1, -1):
result[i] *= right_product
right_product *= nums[i]
return resultclass Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] result = new int[n];
// 计算左侧乘积
int left = 1;
for (int i = 0; i < n; i++) {
result[i] = left;
left *= nums[i];
}
// 计算右侧乘积并合并
int right = 1;
for (int i = n-1; i >= 0; i--) {
result[i] *= right;
right *= nums[i];
}
return result;
}
}class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n = nums.size();
vector<int> result(n, 1);
// 计算左侧乘积
int left = 1;
for (int i = 0; i < n; i++) {
result[i] = left;
left *= nums[i];
}
// 计算右侧乘积并合并
int right = 1;
for (int i = n-1; i >= 0; i--) {
result[i] *= right;
right *= nums[i];
}
return result;
}
};题目描述: 给定数组和滑动窗口大小k,返回每次窗口滑动时的最大值数组。 示例: 输入:nums = [1,3,-1,-3,5,3,6,7], k=3 输出:[3,3,5,5,6,7] 最优解思路: 使用双端队列维护窗口内元素的索引,保证队列头部始终为当前窗口最大值。 时间复杂度:O(n) 空间复杂度:O(k)
from collections import deque
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
dq = deque()
result = []
for i in range(len(nums)):
# 移除超出窗口的元素
if dq and dq[0] == i - k:
dq.popleft()
# 移除小于当前元素的元素
while dq and nums[dq[-1]] < nums[i]:
dq.pop()
dq.append(i)
# 当窗口形成时添加结果
if i >= k - 1:
result.append(nums[dq[0]])
return resultimport java.util.*;
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || k <= 0) return new int[0];
int n = nums.length;
int[] result = new int[n - k + 1];
Deque<Integer> dq = new ArrayDeque<>();
int ri = 0;
for (int i = 0; i < n; i++) {
// 移除超出窗口的元素
if (!dq.isEmpty() && dq.peekFirst() == i - k) {
dq.pollFirst();
}
// 移除小于当前元素的元素
while (!dq.isEmpty() && nums[dq.peekLast()] < nums[i]) {
dq.pollLast();
}
dq.offerLast(i);
// 当窗口形成时添加结果
if (i >= k - 1) {
result[ri++] = nums[dq.peekFirst()];
}
}
return result;
}
}#include <vector>
#include <deque>
using namespace std;
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dq;
vector<int> result;
for (int i = 0; i < nums.size(); i++) {
// 移除超出窗口的元素
if (!dq.empty() && dq.front() == i - k) {
dq.pop_front();
}
// 移除小于当前元素的元素
while (!dq.empty() && nums[dq.back()] < nums[i]) {
dq.pop_back();
}
dq.push_back(i);
// 当窗口形成时添加结果
if (i >= k - 1) {
result.push_back(nums[dq.front()]);
}
}
return result;
}
};题目描述: 给定包含n+1个整数的数组,所有整数在[1,n]范围内,只有一个重复数,找出它。 示例: 输入:[1,3,4,2,2] 输出:2 最优解思路: Floyd判圈算法(快慢指针)。将数组视为链表,重复元素会导致环。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
# 快慢指针
slow = fast = nums[0]
while True:
slow = nums[slow]
fast = nums[nums[fast]]
if slow == fast:
break
# 寻找环入口
slow = nums[0]
while slow != fast:
slow = nums[slow]
fast = nums[fast]
return slowclass Solution {
public int findDuplicate(int[] nums) {
int slow = nums[0];
int fast = nums[0];
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
slow = nums[0];
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}class Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow = nums[0];
int fast = nums[0];
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
slow = nums[0];
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
};题目描述: 设计并实现LRU(最近最少使用)缓存。 最优解思路: 哈希表+双向链表。哈希表存储键到节点的映射,双向链表维护使用顺序。 时间复杂度:O(1) 空间复杂度:O(capacity)
class DLinkedNode:
def __init__(self, key=0, value=0):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.cache = {}
self.capacity = capacity
self.head = DLinkedNode()
self.tail = DLinkedNode()
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key: int) -> int:
if key not in self.cache:
return -1
node = self.cache[key]
self.move_to_head(node)
return node.value
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
node.value = value
self.move_to_head(node)
else:
node = DLinkedNode(key, value)
self.cache[key] = node
self.add_to_head(node)
if len(self.cache) > self.capacity:
removed = self.remove_tail()
del self.cache[removed.key]
def add_to_head(self, node):
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def remove_node(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def move_to_head(self, node):
self.remove_node(node)
self.add_to_head(node)
def remove_tail(self):
node = self.tail.prev
self.remove_node(node)
return nodeimport java.util.*;
class LRUCache {
class DLinkedNode {
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
}
private void addNode(DLinkedNode node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private void removeNode(DLinkedNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void moveToHead(DLinkedNode node) {
removeNode(node);
addNode(node);
}
private DLinkedNode popTail() {
DLinkedNode res = tail.prev;
removeNode(res);
return res;
}
private Map<Integer, DLinkedNode> cache = new HashMap<>();
private int capacity;
private DLinkedNode head, tail;
public LRUCache(int capacity) {
this.capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
DLinkedNode node = cache.get(key);
if (node == null) return -1;
moveToHead(node);
return node.value;
}
public void put(int key, int value) {
DLinkedNode node = cache.get(key);
if (node == null) {
DLinkedNode newNode = new DLinkedNode();
newNode.key = key;
newNode.value = value;
cache.put(key, newNode);
addNode(newNode);
if (cache.size() > capacity) {
DLinkedNode tail = popTail();
cache.remove(tail.key);
}
} else {
node.value = value;
moveToHead(node);
}
}
}#include <unordered_map>
using namespace std;
class LRUCache {
private:
struct DLinkedNode {
int key, value;
DLinkedNode* prev;
DLinkedNode* next;
DLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr) {}
DLinkedNode(int k, int v): key(k), value(v), prev(nullptr), next(nullptr) {}
};
void addToHead(DLinkedNode* node) {
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}
void removeNode(DLinkedNode* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveToHead(DLinkedNode* node) {
removeNode(node);
addToHead(node);
}
DLinkedNode* removeTail() {
DLinkedNode* node = tail->prev;
removeNode(node);
return node;
}
unordered_map<int, DLinkedNode*> cache;
int capacity;
DLinkedNode* head;
DLinkedNode* tail;
public:
LRUCache(int capacity) {
this->capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if (!cache.count(key)) return -1;
DLinkedNode* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
if (!cache.count(key)) {
DLinkedNode* node = new DLinkedNode(key, value);
cache[key] = node;
addToHead(node);
if (cache.size() > capacity) {
DLinkedNode* removed = removeTail();
cache.erase(removed->key);
delete removed;
}
} else {
DLinkedNode* node = cache[key];
node->value = value;
moveToHead(node);
}
}
};题目描述: 给定n个非负整数表示垂直线高度,找出两条线与x轴共同构成的容器可以容纳最多的水。 示例: 输入:[1,8,6,2,5,4,8,3,7] 输出:49 最优解思路: 双指针法:左右指针分别指向数组两端,每次移动较小高度的指针,计算并更新最大面积。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def maxArea(self, height: List[int]) -> int:
left, right = 0, len(height)-1
max_area = 0
while left < right:
area = min(height[left], height[right]) * (right - left)
max_area = max(max_area, area)
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_areaclass Solution {
public int maxArea(int[] height) {
int left = 0, right = height.length - 1;
int maxArea = 0;
while (left < right) {
int h = Math.min(height[left], height[right]);
int area = h * (right - left);
maxArea = Math.max(maxArea, area);
if (height[left] < height[right]) left++;
else right--;
}
return maxArea;
}
}class Solution {
public:
int maxArea(vector<int>& height) {
int left = 0, right = height.size()-1;
int maxArea = 0;
while (left < right) {
int h = min(height[left], height[right]);
maxArea = max(maxArea, h * (right - left));
if (height[left] < height[right]) left++;
else right--;
}
return maxArea;
}
};题目描述: 给定区间集合,合并所有重叠的区间。 示例: 输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 最优解思路: 先按区间起点排序,然后遍历区间,合并重叠区间。 时间复杂度:O(n log n) 空间复杂度:O(1)(不考虑输出空间)
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
if not intervals: return []
intervals.sort(key=lambda x: x[0])
merged = []
for interval in intervals:
if not merged or merged[-1][1] < interval[0]:
merged.append(interval)
else:
merged[-1][1] = max(merged[-1][1], interval[1])
return mergedclass Solution {
public int[][] merge(int[][] intervals) {
if (intervals.length == 0) return new int[0][];
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
LinkedList<int[]> merged = new LinkedList<>();
for (int[] interval : intervals) {
if (merged.isEmpty() || merged.getLast()[1] < interval[0]) {
merged.add(interval);
} else {
merged.getLast()[1] = Math.max(merged.getLast()[1], interval[1]);
}
}
return merged.toArray(new int[merged.size()][]);
}
}class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if (intervals.empty()) return {};
sort(intervals.begin(), intervals.end());
vector<vector<int>> merged;
for (auto& interval : intervals) {
if (merged.empty() || merged.back()[1] < interval[0]) {
merged.push_back(interval);
} else {
merged.back()[1] = max(merged.back()[1], interval[1]);
}
}
return merged;
}
};题目描述: 给定字符串,找出不包含重复字符的最长子串长度。 示例: 输入:“abcabcbb” 输出:3(“abc”) 最优解思路: 滑动窗口+哈希表记录字符最后出现位置。 时间复杂度:O(n) 空间复杂度:O(min(m, n)) 字符集大小
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
char_map = {}
max_len = 0
left = 0
for right, char in enumerate(s):
if char in char_map and char_map[char] >= left:
left = char_map[char] + 1
char_map[char] = right
max_len = max(max_len, right - left + 1)
return max_lenclass Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> map = new HashMap<>();
int maxLen = 0;
int left = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
if (map.containsKey(c) && map.get(c) >= left) {
left = map.get(c) + 1;
}
map.put(c, right);
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
}class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> charMap;
int maxLen = 0;
int left = 0;
for (int right = 0; right < s.size(); right++) {
char c = s[right];
if (charMap.find(c) != charMap.end() && charMap[c] >= left) {
left = charMap[c] + 1;
}
charMap[c] = right;
maxLen = max(maxLen, right - left + 1);
}
return maxLen;
}
};题目描述: 给定字符串,找到最长回文子串。 示例: 输入:“babad” 输出:“bab"或"aba” 最优解思路: 中心扩展法:遍历每个字符作为中心,向两边扩展寻找回文串(分奇偶情况)。 时间复杂度:O(n²) 空间复杂度:O(1)
class Solution:
def longestPalindrome(self, s: str) -> str:
def expand(left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return s[left+1:right]
result = ""
for i in range(len(s)):
# 奇数长度
odd = expand(i, i)
# 偶数长度
even = expand(i, i+1)
if len(odd) > len(result):
result = odd
if len(even) > len(result):
result = even
return resultclass Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expand(s, i, i);
int len2 = expand(s, i, i+1);
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
private int expand(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}
}class Solution {
public:
string longestPalindrome(string s) {
if (s.empty()) return "";
int start = 0, maxLen = 0;
for (int i = 0; i < s.size(); i++) {
int len1 = expand(s, i, i);
int len2 = expand(s, i, i+1);
int len = max(len1, len2);
if (len > maxLen) {
start = i - (len - 1) / 2;
maxLen = len;
}
}
return s.substr(start, maxLen);
}
int expand(string s, int left, int right) {
while (left >= 0 && right < s.size() && s[left] == s[right]) {
left--;
right++;
}
return right - left - 1;
}
};题目描述: 给定整数数组和k,返回出现频率前k高的元素。 示例: 输入:nums = [1,1,1,2,2,3], k=2 输出:[1,2] 最优解思路: 哈希表统计频率,最小堆(优先队列)维护前K个高频元素。 时间复杂度:O(n log k) 空间复杂度:O(n)
import heapq
from collections import Counter
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
count = Counter(nums)
return heapq.nlargest(k, count.keys(), key=count.get)class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> count = new HashMap<>();
for (int num : nums) {
count.put(num, count.getOrDefault(num, 0) + 1);
}
PriorityQueue<Integer> heap = new PriorityQueue<>(
(a, b) -> count.get(a) - count.get(b)
);
for (int num : count.keySet()) {
heap.add(num);
if (heap.size() > k) heap.poll();
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = heap.poll();
}
return result;
}
}#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> count;
for (int num : nums) count[num]++;
auto cmp = [&](int a, int b) { return count[a] > count[b]; };
priority_queue<int, vector<int>, decltype(cmp)> heap(cmp);
for (auto& pair : count) {
heap.push(pair.first);
if (heap.size() > k) heap.pop();
}
vector<int> result(k);
for (int i = k-1; i >= 0; i--) {
result[i] = heap.top();
heap.pop();
}
return result;
}
};题目描述: 给定两个单词,计算将word1转换为word2所需的最少操作数(插入、删除、替换)。 示例: 输入:word1=“horse”, word2=“ros” 输出:3 最优解思路: 动态规划:dp[i][j]表示word1前i个字符到word2前j个字符的编辑距离。 时间复杂度:O(mn) 空间复杂度:O(mn)
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[0]*(n+1) for _ in range(m+1)]
# 初始化
for i in range(m+1): dp[i][0] = i
for j in range(n+1): dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+1):
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
return dp[m][n]class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length(), n = word2.length();
int[][] dp = new int[m+1][n+1];
for (int i = 0; i <= m; i++) dp[i][0] = i;
for (int j = 0; j <= n; j++) dp[0][j] = j;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = 1 + Math.min(dp[i-1][j],
Math.min(dp[i][j-1], dp[i-1][j-1]));
}
}
}
return dp[m][n];
}
}class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
for (int i = 0; i <= m; i++) dp[i][0] = i;
for (int j = 0; j <= n; j++) dp[0][j] = j;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (word1[i-1] == word2[j-1]) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = 1 + min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]});
}
}
}
return dp[m][n];
}
};题目描述: 给定二进制矩阵,找出只包含’1’的最大矩形面积。 示例: 输入: [ [“1”,“0”,“1”,“0”,“0”], [“1”,“0”,“1”,“1”,“1”], [“1”,“1”,“1”,“1”,“1”], [“1”,“0”,“0”,“1”,“0”] ] 输出:6 最优解思路: 按行遍历,计算每列的高度,转化为柱状图最大矩形问题(使用单调栈)。 时间复杂度:O(mn) 空间复杂度:O(n)
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
if not matrix: return 0
m, n = len(matrix), len(matrix[0])
heights = [0] * n
max_area = 0
for i in range(m):
for j in range(n):
heights[j] = heights[j] + 1 if matrix[i][j] == "1" else 0
max_area = max(max_area, self.largestRectangleArea(heights))
return max_area
def largestRectangleArea(self, heights: List[int]) -> int:
stack = [-1]
max_area = 0
for i in range(len(heights)):
while stack[-1] != -1 and heights[stack[-1]] >= heights[i]:
h = heights[stack.pop()]
w = i - stack[-1] - 1
max_area = max(max_area, h * w)
stack.append(i)
while stack[-1] != -1:
h = heights[stack.pop()]
w = len(heights) - stack[-1] - 1
max_area = max(max_area, h * w)
return max_areaclass Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) return 0;
int m = matrix.length, n = matrix[0].length;
int[] heights = new int[n];
int maxArea = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
heights[j] = matrix[i][j] == '1' ? heights[j] + 1 : 0;
}
maxArea = Math.max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
private int largestRectangleArea(int[] heights) {
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
int h = heights[stack.pop()];
int w = i - stack.peek() - 1;
maxArea = Math.max(maxArea, h * w);
}
stack.push(i);
}
while (stack.peek() != -1) {
int h = heights[stack.pop()];
int w = heights.length - stack.peek() - 1;
maxArea = Math.max(maxArea, h * w);
}
return maxArea;
}
}class Solution {
public:
int maximalRectangle(vector<vector<char>>& matrix) {
if (matrix.empty()) return 0;
int m = matrix.size(), n = matrix[0].size();
vector<int> heights(n, 0);
int maxArea = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
heights[j] = matrix[i][j] == '1' ? heights[j] + 1 : 0;
}
maxArea = max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
int largestRectangleArea(vector<int>& heights) {
stack<int> st;
st.push(-1);
int maxArea = 0;
for (int i = 0; i < heights.size(); i++) {
while (st.top() != -1 && heights[st.top()] >= heights[i]) {
int h = heights[st.top()]; st.pop();
int w = i - st.top() - 1;
maxArea = max(maxArea, h * w);
}
st.push(i);
}
while (st.top() != -1) {
int h = heights[st.top()]; st.pop();
int w = heights.size() - st.top() - 1;
maxArea = max(maxArea, h * w);
}
return maxArea;
}
};题目描述: 给定二叉树,找出路径和最大的路径(路径是树中任意节点间的序列)。 示例: 输入:[-10,9,20,null,null,15,7] 输出:42(15→20→7) 最优解思路: 递归计算每个节点的贡献值(以该节点为起点的最大路径和),同时更新全局最大路径和。 时间复杂度:O(n) 空间复杂度:O(h)
class Solution:
def maxPathSum(self, root: TreeNode) -> int:
self.max_sum = float('-inf')
def max_gain(node):
if not node: return 0
left_gain = max(max_gain(node.left), 0)
right_gain = max(max_gain(node.right), 0)
# 当前节点为根的路径和
price_newpath = node.val + left_gain + right_gain
self.max_sum = max(self.max_sum, price_newpath)
# 返回当前节点的最大贡献值
return node.val + max(left_gain, right_gain)
max_gain(root)
return self.max_sumclass Solution {
int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxGain(root);
return maxSum;
}
private int maxGain(TreeNode node) {
if (node == null) return 0;
int leftGain = Math.max(maxGain(node.left), 0);
int rightGain = Math.max(maxGain(node.right), 0);
int priceNewpath = node.val + leftGain + rightGain;
maxSum = Math.max(maxSum, priceNewpath);
return node.val + Math.max(leftGain, rightGain);
}
}class Solution {
public:
int maxPathSum(TreeNode* root) {
int maxSum = INT_MIN;
maxGain(root, maxSum);
return maxSum;
}
int maxGain(TreeNode* node, int& maxSum) {
if (!node) return 0;
int leftGain = max(maxGain(node->left, maxSum), 0);
int rightGain = max(maxGain(node->right, maxSum), 0);
int priceNewpath = node->val + leftGain + rightGain;
maxSum = max(maxSum, priceNewpath);
return node->val + max(leftGain, rightGain);
}
};题目描述: 实现Trie数据结构:insert, search, startsWith。 最优解思路: 使用嵌套字典实现,每个节点包含子节点映射和单词结束标志。 时间复杂度:O(L)(L为单词长度) 空间复杂度:O(N*L)(N为插入单词数)
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word: str) -> None:
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end = True
def search(self, word: str) -> bool:
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end
def startsWith(self, prefix: str) -> bool:
node = self.root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return Trueclass TrieNode {
public Map<Character, TrieNode> children;
public boolean isEnd;
public TrieNode() {
children = new HashMap<>();
isEnd = false;
}
}
class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
public void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
node.children.putIfAbsent(c, new TrieNode());
node = node.children.get(c);
}
node.isEnd = true;
}
public boolean search(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
if (!node.children.containsKey(c)) return false;
node = node.children.get(c);
}
return node.isEnd;
}
public boolean startsWith(String prefix) {
TrieNode node = root;
for (char c : prefix.toCharArray()) {
if (!node.children.containsKey(c)) return false;
node = node.children.get(c);
}
return true;
}
}class TrieNode {
public:
unordered_map<char, TrieNode*> children;
bool isEnd;
TrieNode() : isEnd(false) {}
};
class Trie {
private:
TrieNode* root;
public:
Trie() {
root = new TrieNode();
}
void insert(string word) {
TrieNode* node = root;
for (char c : word) {
if (!node->children.count(c)) {
node->children[c] = new TrieNode();
}
node = node->children[c];
}
node->isEnd = true;
}
bool search(string word) {
TrieNode* node = root;
for (char c : word) {
if (!node->children.count(c)) return false;
node = node->children[c];
}
return node->isEnd;
}
bool startsWith(string prefix) {
TrieNode* node = root;
for (char c : prefix) {
if (!node->children.count(c)) return false;
node = node->children[c];
}
return true;
}
};题目描述: 判断链表是否为回文链表。 示例: 输入:1→2→2→1 输出:true 最优解思路: 快慢指针找中点,反转后半部分,比较两部分是否相同。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if not head or not head.next: return True
# 找中点
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 反转后半部分
prev, curr = None, slow
while curr:
next_temp = curr.next
curr.next = prev
prev = curr
curr = next_temp
# 比较两部分
p1, p2 = head, prev
while p2: # 只需比较后半部分长度
if p1.val != p2.val:
return False
p1 = p1.next
p2 = p2.next
return Trueclass Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) return true;
// 找中点
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 反转后半部分
ListNode prev = null, curr = slow;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
// 比较两部分
ListNode p1 = head, p2 = prev;
while (p2 != null) {
if (p1.val != p2.val) return false;
p1 = p1.next;
p2 = p2.next;
}
return true;
}
}class Solution {
public:
bool isPalindrome(ListNode* head) {
if (!head || !head->next) return true;
// 找中点
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
// 反转后半部分
ListNode* prev = nullptr;
ListNode* curr = slow;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
// 比较两部分
ListNode* p1 = head;
ListNode* p2 = prev;
while (p2) {
if (p1->val != p2->val) return false;
p1 = p1->next;
p2 = p2->next;
}
return true;
}
};题目描述: 先从左往右,再从右往左进行层序遍历。 示例: 输入:[3,9,20,null,null,15,7] 输出:[[3],[20,9],[15,7]] 最优解思路: BFS遍历,使用双端队列根据层级决定插入方向。 时间复杂度:O(n) 空间复杂度:O(n)
class Solution:
def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
if not root: return []
result = []
queue = deque([root])
level = 0
while queue:
size = len(queue)
current_level = deque()
for _ in range(size):
node = queue.popleft()
if level % 2 == 0:
current_level.append(node.val)
else:
current_level.appendleft(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
result.append(list(current_level))
level += 1
return resultclass Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean leftToRight = true;
while (!queue.isEmpty()) {
int size = queue.size();
LinkedList<Integer> level = new LinkedList<>();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (leftToRight) {
level.addLast(node.val);
} else {
level.addFirst(node.val);
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(level);
leftToRight = !leftToRight;
}
return result;
}
}class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
bool leftToRight = true;
while (!q.empty()) {
int size = q.size();
vector<int> level(size);
for (int i = 0; i < size; i++) {
TreeNode* node = q.front(); q.pop();
int index = leftToRight ? i : size - 1 - i;
level[index] = node->val;
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
result.push_back(level);
leftToRight = !leftToRight;
}
return result;
}
};题目描述: 给定链表,返回环的入口节点,无环返回null。 示例: 输入:head = [3,2,0,-4], pos=1 输出:值为2的节点 最优解思路: Floyd算法:快慢指针相遇后,慢指针与从起点出发的指针再次相遇点为入口。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
ptr = head
while ptr != slow:
ptr = ptr.next
slow = slow.next
return ptr
return Nonepublic class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr;
}
}
return null;
}
}class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
ListNode *ptr = head;
while (ptr != slow) {
ptr = ptr->next;
slow = slow->next;
}
return ptr;
}
}
return nullptr;
}
};题目描述: 合并k个升序链表。 示例: 输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 最优解思路: 使用最小堆(优先队列)维护所有链表当前节点。 时间复杂度:O(N log k) 空间复杂度:O(k)
import heapq
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
dummy = ListNode()
curr = dummy
heap = []
for i, node in enumerate(lists):
if node:
heapq.heappush(heap, (node.val, i, node))
while heap:
val, idx, node = heapq.heappop(heap)
curr.next = node
curr = curr.next
if node.next:
heapq.heappush(heap, (node.next.val, idx, node.next))
return dummy.nextclass Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
PriorityQueue<ListNode> heap = new PriorityQueue<>((a, b) -> a.val - b.val);
ListNode dummy = new ListNode();
ListNode curr = dummy;
for (ListNode node : lists) {
if (node != null) heap.offer(node);
}
while (!heap.isEmpty()) {
ListNode node = heap.poll();
curr.next = node;
curr = curr.next;
if (node.next != null) heap.offer(node.next);
}
return dummy.next;
}
}class Solution {
public:
struct Compare {
bool operator()(ListNode* a, ListNode* b) {
return a->val > b->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, Compare> heap;
ListNode dummy;
ListNode* curr = &dummy;
for (ListNode* node : lists) {
if (node) heap.push(node);
}
while (!heap.empty()) {
ListNode* node = heap.top(); heap.pop();
curr->next = node;
curr = curr->next;
if (node->next) heap.push(node->next);
}
return dummy.next;
}
};题目描述: 给定整数数组,找到最长严格递增子序列的长度。 示例: 输入:[10,9,2,5,3,7,101,18] 输出:4(子序列[2,3,7,101]) 最优解思路: 动态规划+贪心+二分查找:维护一个tails数组,tails[i]表示长度为i+1的上升子序列的最小尾部值。 时间复杂度:O(n log n) 空间复杂度:O(n)
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
tails = []
for num in nums:
# 二分查找插入位置
left, right = 0, len(tails)
while left < right:
mid = (left + right) // 2
if tails[mid] < num:
left = mid + 1
else:
right = mid
if left == len(tails):
tails.append(num)
else:
tails[left] = num
return len(tails)class Solution {
public int lengthOfLIS(int[] nums) {
int[] tails = new int[nums.length];
int size = 0;
for (int num : nums) {
int left = 0, right = size;
while (left < right) {
int mid = left + (right - left) / 2;
if (tails[mid] < num) {
left = mid + 1;
} else {
right = mid;
}
}
if (left == size) {
tails[size++] = num;
} else {
tails[left] = num;
}
}
return size;
}
}class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> tails;
for (int num : nums) {
auto it = lower_bound(tails.begin(), tails.end(), num);
if (it == tails.end()) {
tails.push_back(num);
} else {
*it = num;
}
}
return tails.size();
}
};题目描述: 给定数组表示沿街房屋金额,不能偷相邻房屋,求最大金额。 示例: 输入:[2,7,9,3,1] 输出:12(2+9+1) 最优解思路: 动态规划:dp[i] = max(dp[i-1], dp[i-2] + nums[i]),可优化为滚动数组。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def rob(self, nums: List[int]) -> int:
prev_max, curr_max = 0, 0
for num in nums:
temp = curr_max
curr_max = max(prev_max + num, curr_max)
prev_max = temp
return curr_maxclass Solution {
public int rob(int[] nums) {
int prev = 0, curr = 0;
for (int num : nums) {
int temp = curr;
curr = Math.max(prev + num, curr);
prev = temp;
}
return curr;
}
}class Solution {
public:
int rob(vector<int>& nums) {
int prev = 0, curr = 0;
for (int num : nums) {
int temp = curr;
curr = max(prev + num, curr);
prev = temp;
}
return curr;
}
};题目描述: 二叉树结构房屋,不能偷相邻节点,求最大金额。 示例: 输入:[3,2,3,null,3,null,1] 输出:7(3+3+1) 最优解思路: 树形DP:每个节点返回[偷当前节点的最大收益, 不偷当前节点的最大收益]。 时间复杂度:O(n) 空间复杂度:O(h)
class Solution:
def rob(self, root: TreeNode) -> int:
def dfs(node):
if not node: return (0, 0)
left = dfs(node.left)
right = dfs(node.right)
# 偷当前节点:当前值+不偷左右子节点
rob = node.val + left[1] + right[1]
# 不偷当前节点:左右子节点的最大值之和
not_rob = max(left) + max(right)
return (rob, not_rob)
return max(dfs(root))class Solution {
public int rob(TreeNode root) {
int[] result = dfs(root);
return Math.max(result[0], result[1]);
}
private int[] dfs(TreeNode node) {
if (node == null) return new int[]{0, 0};
int[] left = dfs(node.left);
int[] right = dfs(node.right);
int rob = node.val + left[1] + right[1];
int notRob = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return new int[]{rob, notRob};
}
}class Solution {
public:
int rob(TreeNode* root) {
auto result = dfs(root);
return max(result[0], result[1]);
}
pair<int, int> dfs(TreeNode* node) {
if (!node) return {0, 0};
auto left = dfs(node->left);
auto right = dfs(node->right);
int rob = node->val + left.second + right.second;
int notRob = max(left.first, left.second) + max(right.first, right.second);
return {rob, notRob};
}
};题目描述: m x n矩阵,每行从左到右升序,每列从上到下升序,判断target是否存在。 示例: 输入: [ [1,4,7,11,15], [2,5,8,12,19], [3,6,9,16,22], [10,13,14,17,24], [18,21,23,26,30] ], target=5 输出:true 最优解思路: 从右上角开始搜索,比target大则左移,比target小则下移。 时间复杂度:O(m+n) 空间复杂度:O(1)
class Solution:
def searchMatrix(self, matrix, target):
if not matrix: return False
row, col = 0, len(matrix[0])-1
while row < len(matrix) and col >= 0:
if matrix[row][col] == target:
return True
elif matrix[row][col] > target:
col -= 1
else:
row += 1
return Falseclass Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0) return false;
int row = 0, col = matrix[0].length - 1;
while (row < matrix.length && col >= 0) {
if (matrix[row][col] == target) return true;
else if (matrix[row][col] > target) col--;
else row++;
}
return false;
}
}class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if (matrix.empty()) return false;
int row = 0, col = matrix[0].size()-1;
while (row < matrix.size() && col >= 0) {
if (matrix[row][col] == target) return true;
else if (matrix[row][col] > target) col--;
else row++;
}
return false;
}
};题目描述: 给定正整数n,找到若干个完全平方数(1,4,9,…)使它们的和为n,返回最少个数。 示例: 输入:n=12 输出:3(4+4+4) 最优解思路: 动态规划:dp[i]表示和为i的最小平方数个数,dp[i]=min(dp[i], dp[i-j*j]+1)。 时间复杂度:O(n√n) 空间复杂度:O(n)
class Solution:
def numSquares(self, n: int) -> int:
dp = [float('inf')]*(n+1)
dp[0] = 0
for i in range(1, n+1):
j = 1
while j*j <= i:
dp[i] = min(dp[i], dp[i-j*j]+1)
j += 1
return dp[n]class Solution {
public int numSquares(int n) {
int[] dp = new int[n+1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j*j <= i; j++) {
dp[i] = Math.min(dp[i], dp[i - j*j] + 1);
}
}
return dp[n];
}
}class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1, INT_MAX);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j*j <= i; j++) {
dp[i] = min(dp[i], dp[i - j*j] + 1);
}
}
return dp[n];
}
};题目描述: 将数组中的0移动到末尾,保持非零元素相对顺序。 示例: 输入:[0,1,0,3,12] 输出:[1,3,12,0,0] 最优解思路: 双指针:左指针指向已处理序列尾部,右指针遍历数组,非零元素交换到左侧。 时间复杂度:O(n) 空间复杂度:O(1)
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
left = 0
for right in range(len(nums)):
if nums[right] != 0:
nums[left], nums[right] = nums[right], nums[left]
left += 1class Solution {
public void moveZeroes(int[] nums) {
int left = 0;
for (int right = 0; right < nums.length; right++) {
if (nums[right] != 0) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++;
}
}
}
}class Solution {
public:
void moveZeroes(vector<int>& nums) {
int left = 0;
for (int right = 0; right < nums.size(); right++) {
if (nums[right] != 0) {
swap(nums[left], nums[right]);
left++;
}
}
}
};题目描述: 设计算法实现二叉树的序列化与反序列化。 最优解思路: 使用DFS(前序遍历)序列化,特殊符号表示空节点。 时间复杂度:O(n) 空间复杂度:O(n)
class Codec:
def serialize(self, root):
if not root: return "X"
left = self.serialize(root.left)
right = self.serialize(root.right)
return str(root.val) + "," + left + "," + right
def deserialize(self, data):
nodes = data.split(",")
return self.buildTree(iter(nodes))
def buildTree(self, nodes):
val = next(nodes)
if val == "X": return None
node = TreeNode(int(val))
node.left = self.buildTree(nodes)
node.right = self.buildTree(nodes)
return nodepublic class Codec {
public String serialize(TreeNode root) {
if (root == null) return "X";
String left = serialize(root.left);
String right = serialize(root.right);
return root.val + "," + left + "," + right;
}
public TreeNode deserialize(String data) {
String[] nodes = data.split(",");
return buildTree(new LinkedList<>(Arrays.asList(nodes)));
}
private TreeNode buildTree(Queue<String> nodes) {
String val = nodes.poll();
if (val.equals("X")) return null;
TreeNode node = new TreeNode(Integer.parseInt(val));
node.left = buildTree(nodes);
node.right = buildTree(nodes);
return node;
}
}class Codec {
public:
string serialize(TreeNode* root) {
if (!root) return "X";
return to_string(root->val) + "," + serialize(root->left) + "," + serialize(root->right);
}
TreeNode* deserialize(string data) {
stringstream ss(data);
return buildTree(ss);
}
TreeNode* buildTree(stringstream& ss) {
string val;
getline(ss, val, ',');
if (val == "X") return nullptr;
TreeNode* node = new TreeNode(stoi(val));
node->left = buildTree(ss);
node->right = buildTree(ss);
return node;
}
};题目描述: 给定编码字符串k[encoded_string],返回解码后字符串。 示例: 输入:“3[a]2[bc]” 输出:“aaabcbc” 最优解思路: 使用栈处理嵌套结构,遇到’]‘时出栈直到’[',再出栈数字。 时间复杂度:O(n) 空间复杂度:O(n)
class Solution:
def decodeString(self, s: str) -> str:
stack = []
curr_num = 0
curr_str = ""
for char in s:
if char == '[':
stack.append(curr_str)
stack.append(curr_num)
curr_str = ""
curr_num = 0
elif char == ']':
num = stack.pop()
prev_str = stack.pop()
curr_str = prev_str + num * curr_str
elif char.isdigit():
curr_num = curr_num * 10 + int(char)
else:
curr_str += char
return curr_strclass Solution {
public String decodeString(String s) {
Stack<Integer> numStack = new Stack<>();
Stack<String> strStack = new Stack<>();
int currNum = 0;
StringBuilder currStr = new StringBuilder();
for (char c : s.toCharArray()) {
if (Character.isDigit(c)) {
currNum = currNum * 10 + (c - '0');
} else if (c == '[') {
numStack.push(currNum);
strStack.push(currStr.toString());
currNum = 0;
currStr = new StringBuilder();
} else if (c == ']') {
int num = numStack.pop();
StringBuilder prevStr = new StringBuilder(strStack.pop());
for (int i = 0; i < num; i++) {
prevStr.append(currStr);
}
currStr = prevStr;
} else {
currStr.append(c);
}
}
return currStr.toString();
}
}class Solution {
public:
string decodeString(string s) {
stack<int> numStack;
stack<string> strStack;
int currNum = 0;
string currStr = "";
for (char c : s) {
if (isdigit(c)) {
currNum = currNum * 10 + (c - '0');
} else if (c == '[') {
numStack.push(currNum);
strStack.push(currStr);
currNum = 0;
currStr = "";
} else if (c == ']') {
int num = numStack.top(); numStack.pop();
string prevStr = strStack.top(); strStack.pop();
string temp;
for (int i = 0; i < num; i++) {
temp += currStr;
}
currStr = prevStr + temp;
} else {
currStr += c;
}
}
return currStr;
}
};题目描述: 判断数组是否可分割成两个和相等的子集。 示例: 输入:[1,5,11,5] 输出:true([1,5,5]和[11]) 最优解思路: 转化为背包问题:能否用数组中元素拼出sum/2。 时间复杂度:O(n*sum) 空间复杂度:O(sum)
class Solution:
def canPartition(self, nums: List[int]) -> bool:
total = sum(nums)
if total % 2 != 0: return False
target = total // 2
dp = [False]*(target+1)
dp[0] = True
for num in nums:
for j in range(target, num-1, -1):
if dp[j-num]:
dp[j] = True
return dp[target]class Solution {
public boolean canPartition(int[] nums) {
int total = 0;
for (int num : nums) total += num;
if (total % 2 != 0) return false;
int target = total / 2;
boolean[] dp = new boolean[target+1];
dp[0] = true;
for (int num : nums) {
for (int j = target; j >= num; j--) {
if (dp[j - num]) {
dp[j] = true;
}
}
}
return dp[target];
}
}class Solution {
public:
bool canPartition(vector<int>& nums) {
int total = accumulate(nums.begin(), nums.end(), 0);
if (total % 2 != 0) return false;
int target = total / 2;
vector<bool> dp(target+1, false);
dp[0] = true;
for (int num : nums) {
for (int j = target; j >= num; j--) {
if (dp[j - num]) {
dp[j] = true;
}
}
}
return dp[target];
}
};题目描述: 找出二叉树中和等于目标值的路径数量(路径不需从根开始)。 示例: 输入:root=[10,5,-3,3,2,null,11,3,-2,null,1], sum=8 输出:3 最优解思路: 前缀和+DFS:用哈希表存储路径前缀和,回溯时更新哈希表。 时间复杂度:O(n) 空间复杂度:O(n)
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> int:
from collections import defaultdict
prefixSum = defaultdict(int)
prefixSum[0] = 1 # 初始前缀和为0的路径有1条
self.count = 0
def dfs(node, curr_sum):
if not node: return
curr_sum += node.val
# 查找前缀和为curr_sum - target的路径数量
self.count += prefixSum.get(curr_sum - sum, 0)
prefixSum[curr_sum] += 1
dfs(node.left, curr_sum)
dfs(node.right, curr_sum)
prefixSum[curr_sum] -= 1 # 回溯
dfs(root, 0)
return self.countclass Solution {
public int pathSum(TreeNode root, int sum) {
Map<Integer, Integer> prefixSum = new HashMap<>();
prefixSum.put(0, 1);
int[] count = new int[1];
dfs(root, 0, sum, prefixSum, count);
return count[0];
}
private void dfs(TreeNode node, int currSum, int target, Map<Integer, Integer> prefixSum, int[] count) {
if (node == null) return;
currSum += node.val;
count[0] += prefixSum.getOrDefault(currSum - target, 0);
prefixSum.put(currSum, prefixSum.getOrDefault(currSum, 0) + 1);
dfs(node.left, currSum, target, prefixSum, count);
dfs(node.right, currSum, target, prefixSum, count);
prefixSum.put(currSum, prefixSum.get(currSum) - 1);
}
}class Solution {
public:
int pathSum(TreeNode* root, int sum) {
unordered_map<int, int> prefixSum;
prefixSum[0] = 1;
int count = 0;
dfs(root, 0, sum, prefixSum, count);
return count;
}
void dfs(TreeNode* node, int currSum, int target, unordered_map<int, int>& prefixSum, int& count) {
if (!node) return;
currSum += node->val;
count += prefixSum[currSum - target];
prefixSum[currSum]++;
dfs(node->left, currSum, target, prefixSum, count);
dfs(node->right, currSum, target, prefixSum, count);
prefixSum[currSum]--;
}
};题目描述: 计算字符串中回文子串的数量。 示例: 输入:“abc” 输出:3(“a”,“b”,“c”) 最优解思路: 中心扩展法:以每个字符(或字符间)为中心向两边扩展统计回文串。 时间复杂度:O(n²) 空间复杂度:O(1)
class Solution:
def countSubstrings(self, s: str) -> int:
n = len(s)
count = 0
for center in range(2*n-1):
left = center // 2
right = left + center % 2
while left >= 0 and right < n and s[left] == s[right]:
count += 1
left -= 1
right += 1
return countclass Solution {
public int countSubstrings(String s) {
int n = s.length();
int count = 0;
for (int center = 0; center < 2*n-1; center++) {
int left = center / 2;
int right = left + center % 2;
while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
count++;
left--;
right++;
}
}
return count;
}
}class Solution {
public:
int countSubstrings(string s) {
int n = s.size();
int count = 0;
for (int center = 0; center < 2*n-1; center++) {
int left = center / 2;
int right = left + center % 2;
while (left >= 0 && right < n && s[left] == s[right]) {
count++;
left--;
right++;
}
}
return count;
}
};题目描述: 给定两个大小分别为m和n的正序数组,找出中位数。 示例: 输入:nums1=[1,3], nums2=[2] 输出:2.0 最优解思路: 二分查找:在两个数组中找到分割线,使左边元素个数等于右边(或差1)。 时间复杂度:O(log(min(m,n))) 空间复杂度:O(1)
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
if len(nums1) > len(nums2):
nums1, nums2 = nums2, nums1
m, n = len(nums1), len(nums2)
left, right = 0, m
total_left = (m + n + 1) // 2
while left < right:
i = (left + right + 1) // 2
j = total_left - i
if nums1[i-1] > nums2[j]:
right = i - 1
else:
left = i
i = left
j = total_left - i
nums1_left = float('-inf') if i == 0 else nums1[i-1]
nums1_right = float('inf') if i == m else nums1[i]
nums2_left = float('-inf') if j == 0 else nums2[j-1]
nums2_right = float('inf') if j == n else nums2[j]
if (m + n) % 2 == 1:
return max(nums1_left, nums2_left)
else:
return (max(nums1_left, nums2_left) + min(nums1_right, nums2_right)) / 2class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if (nums1.length > nums2.length) {
int[] temp = nums1;
nums1 = nums2;
nums2 = temp;
}
int m = nums1.length, n = nums2.length;
int left = 0, right = m;
int totalLeft = (m + n + 1) / 2;
while (left < right) {
int i = (left + right + 1) / 2;
int j = totalLeft - i;
if (nums1[i-1] > nums2[j]) {
right = i - 1;
} else {
left = i;
}
}
int i = left, j = totalLeft - i;
int nums1Left = i == 0 ? Integer.MIN_VALUE : nums1[i-1];
int nums1Right = i == m ? Integer.MAX_VALUE : nums1[i];
int nums2Left = j == 0 ? Integer.MIN_VALUE : nums2[j-1];
int nums2Right = j == n ? Integer.MAX_VALUE : nums2[j];
if ((m + n) % 2 == 1) {
return Math.max(nums1Left, nums2Left);
} else {
return (Math.max(nums1Left, nums2Left) + Math.min(nums1Right, nums2Right)) / 2.0;
}
}
}class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size()) {
swap(nums1, nums2);
}
int m = nums1.size(), n = nums2.size();
int left = 0, right = m;
int total_left = (m + n + 1) / 2;
while (left < right) {
int i = (left + right + 1) / 2;
int j = total_left - i;
if (nums1[i-1] > nums2[j]) {
right = i - 1;
} else {
left = i;
}
}
int i = left, j = total_left - i;
int nums1_left = i == 0 ? INT_MIN : nums1[i-1];
int nums1_right = i == m ? INT_MAX : nums1[i];
int nums2_left = j == 0 ? INT_MIN : nums2[j-1];
int nums2_right = j == n ? INT_MAX : nums2[j];
if ((m + n) % 2 == 1) {
return max(nums1_left, nums2_left);
} else {
return (max(nums1_left, nums2_left) + min(nums1_right, nums2_right)) / 2.0;
}
}
};成功没有捷径,但正确的方向和方法能让你的努力事半功倍。坚持每天解决一个问题,三个月后你会遇见不一样的自己。