LeetCode 算法题解精编(题号 1601 至 2000)
目录
- 1602. 二叉树中最近的右侧节点
- 1611. 整数归零的最少操作步数
- 1612. 二叉表达式树等价判定
- 1621. K 条不重叠线段的计数
- 1625. 旋转与累加后的字典序最小字符串
- 1631. 路径最小体力消耗
- 1632. 矩阵秩变换
- 1634. 多项式链表求和
- 1641. 字典序元音字符串计数
- 1643. 第 K 小的指令序列
- 1644. 带父指针的二叉树最近公共祖先
- 1650. 带子节点指针的二叉树最近公共祖先
- 1652. 炸弹解密
- 1653. 字符串平衡的最小删除量
- 1657. 字符串接近性判定
- 1658. 将 x 归零的最少操作
- 1662. 字符串数组等价检查
- 1663. 给定数值的最小字典序字符串
- 1664. 平衡数组方案数
- 1666. 二叉树换根
- 1668. 最大重复子串
- 1669. 链表区间合并
- 1673. 最具竞争力的子序列
- 1676. 多节点二叉树最近公共祖先
- 1680. 连续二进制拼接
- 1682. 回文子序列计数 II
- 1684. 一致字符串计数
- 1686. 石子游戏 VI
- 1690. 石子游戏 VII
- 1696. 跳跃游戏 VI
- 1697. 边长限制下的路径可达性
- 1700. 无法吃午餐的学生数
- 1702. 修改后的最大二进制串
- 1704. 字符串两半相似性
- 1705. 最多吃掉的苹果数
- 1724. 边长限制下的路径可达性 II
- 1732. 最高海拔
- 1735. 乘积数组方案数
- 1738. 第 K 大异或坐标值
- 1740. 二叉树中两节点距离
- 1742. 盒中小球的最大数量
- 1752. 数组排序与轮转检查
- 1753. 移除石子的最大得分
- 1766. 互质树
- 1768. 交替合并字符串
- 1773. 按规则匹配的物品计数
- 1780. 三的幂和表示判定
- 1785. 达到目标和的最少元素
- 1793. 好子数组的最大分数
- 1796. 字符串中第二大的数字
- 1799. N 次操作后的最大得分
- 1801. 积压订单总数
- 1802. 有界数组指定下标最大值
- 1803. 异或值在范围内的数对计数
- 1804. 前缀树实现 II
- 1805. 字符串中不同整数计数
- 1806. 还原排列的最少步数
- 1807. 替换字符串中的括号内容
- 1808. 好因子的最大数目
- 1812. 棋盘格子颜色判定
- 1813. 句子相似性 III
- 1814. 好对子计数
- 1815. 新鲜甜甜圈最多组数
- 1817. 用户活跃分钟数
- 1819. 序列中不同最大公约数计数
- 1822. 数组元素积的符号
- 1823. 游戏获胜者
- 1824. 最少侧跳次数
- 1825. MK 平均值
- 1827. 数组递增的最少操作
- 1828. 圆内点计数
- 1830. 字符串有序的最少操作
- 1835. 所有数对按位与的异或和
- 1848. 目标元素最小距离
- 1852. 子数组数字种类数
- 1862. 向下取整的数对和
- 1863. 子集异或总和求和
- 1866. 恰好 K 根木棍可见的排列数
- 1872. 石子游戏 VIII
- 1874. 两数组最小乘积和
- 1883. 准时到达的最小跳过休息次数
- 1884. 两枚鸡蛋掉落
- 1885. 数对统计
- 1901. 二维峰值查找
- 1902. 由插入顺序求二叉搜索树深度
- 1908. Nim 游戏 II
- 1911. 最大交替子序列和
- 1916. 蚁群筑房顺序统计
- 1922. 好数字计数
- 1927. 求和博弈
- 1944. 队列中可见人数
- 1953. 最大工作周数
- 1954. 收集足够苹果的最小周长
- 1969. 最小非零乘积
- 1971. 图中路径存在性
- 1973. 值等于子节点和的节点
- 1976. 到达目的地方案数
- 1979. 数组最大公约数
- 1982. 从子集和还原数组
- 1985. 数组中第 K 大整数
- 1989. 捉迷藏可捕获最大人数
- 1992. 农场组查找
- 1997. 访问完所有房间的第一天
- 1998. 数组最大公因数排序
- 1999. 仅由两个数字组成的最小倍数
1602. 二叉树中最近的右侧节点
标签:二叉树
1611. 整数归零的最少操作步数
标签:九连环
1612. 二叉表达式树等价判定
标签:二叉树
1621. K 条不重叠线段的计数
标签:组合数学
1625. 旋转与累加后的字典序最小字符串
给定一个偶数长度、仅含数字 0-9 的字符串 s,以及两个整数 a 和 b。允许执行以下两种操作任意次:
- 累加操作:将
a加到所有奇数下标(0-based)的数字上,超过 9 则取模 10。 - 轮转操作:将字符串向右轮转
b位。
求能得到的字典序最小的字符串。
示例:
输入:s = "5525", a = 9, b = 2 输出:"2050"
输入:s = "74", a = 5, b = 1 输出:"24"
输入:s = "0011", a = 4, b = 2 输出:"0011"
采用 BFS 遍历所有可达状态,记录已访问字符串防止重复:
class Solution {
public:
string findLexSmallestString(string s, int a, int b) {
queue<string> bfsQueue;
unordered_set<string> seen;
bfsQueue.push(s);
seen.insert(s);
string best = s;
while (!bfsQueue.empty()) {
string cur = bfsQueue.front();
bfsQueue.pop();
if (cur < best) best = cur;
// 累加操作
string nxt = cur;
for (int i = 1; i < (int)nxt.size(); i += 2) {
nxt[i] = (nxt[i] - '0' + a) % 10 + '0';
}
if (seen.find(nxt) == seen.end()) {
seen.insert(nxt);
bfsQueue.push(nxt);
}
// 轮转操作
int n = cur.size();
string rot = cur.substr(n - b) + cur.substr(0, n - b);
if (seen.find(rot) == seen.end()) {
seen.insert(rot);
bfsQueue.push(rot);
}
}
return best;
}
};
1631. 路径最小体力消耗
标签:广度优先搜索
1632. 矩阵秩变换
标签:并查集
1634. 多项式链表求和
标签:单链表
1641. 字典序元音字符串计数
标签:组合数学
1643. 第 K 小的指令序列
标签:全排列
1644. 带父指针的二叉树最近公共祖先
标签:最近公共祖先
1650. 带子节点指针的二叉树最近公共祖先
标签:最近公共祖先
1652. 炸弹解密
标签:循环数组
1653. 字符串平衡的最小删除量
给定仅含字符 'a' 和 'b' 的字符串 s。平衡的定义:不存在 i < j 使得 s[i]='b' 且 s[j]='a'。返回使字符串平衡的最少删除次数。
示例:
输入:s = "aababbab" 输出:2
输入:s = "bbaaaaabb" 输出:2
使用前缀统计 'b' 数量和后缀统计 'a' 数量,枚举分割点:
class Solution {
public:
int minimumDeletions(string s) {
int n = s.size();
vector<int> bBefore(n + 1, 0);
vector<int> aAfter(n + 1, 0);
for (int i = 0; i < n; i++)
bBefore[i + 1] = bBefore[i] + (s[i] == 'b');
for (int i = n - 1; i >= 0; i--)
aAfter[i] = aAfter[i + 1] + (s[i] == 'a');
int minCost = n;
for (int i = 0; i <= n; i++)
minCost = min(minCost, bBefore[i] + aAfter[i]);
return minCost;
}
};
1657. 字符串接近性判定
两种操作可将一个字符串变换为另一个:(1) 交换任意两个现有字符的位置;(2) 将某字符的全部出现与另一现有字符的全部出现互换。判断 word1 和 word2 是否接近。
示例:
输入:word1 = "abc", word2 = "bca" 输出:true
输入:word1 = "a", word2 = "aa" 输出:false
输入:word1 = "cabbba", word2 = "abbccc" 输出:true
核心条件:两字符串长度相等、出现的字符集相同、频率的多重集相同。
class Solution {
public:
bool closeStrings(string w1, string w2) {
if (w1.size() != w2.size()) return false;
int cnt1[26] = {0}, cnt2[26] = {0};
for (char c : w1) cnt1[c - 'a']++;
for (char c : w2) cnt2[c - 'a']++;
for (int i = 0; i < 26; i++)
if ((cnt1[i] > 0) != (cnt2[i] > 0)) return false;
sort(cnt1, cnt1 + 26);
sort(cnt2, cnt2 + 26);
for (int i = 0; i < 26; i++)
if (cnt1[i] != cnt2[i]) return false;
return true;
}
};
1658. 将 x 归零的最少操作
标签:搜索
1662. 字符串数组等价检查
标签:基础题
1663. 给定数值的最小字典序字符串
标签:基础题
1664. 平衡数组方案数
标签:基础题
1666. 二叉树换根
标签:二叉树
1668. 最大重复子串
标签:KMP 算法
1669. 链表区间合并
标签:链表
1673. 最具竞争力的子序列
标签:单调栈
1676. 多节点二叉树最近公共祖先
标签:最近公共祖先
1680. 连续二进制拼接
标签:位运算
1682. 回文子序列计数 II
标签:高维动态规划
1684. 一致字符串计数
标签:基础题
1686. 石子游戏 VI
标签:博弈论
1690. 石子游戏 VII
标签:博弈论
1696. 跳跃游戏 VI
标签:数列动态规划
1697. 边长限制下的路径可达性
标签:并查集
1700. 无法吃午餐的学生数
标签:队列模拟
1702. 修改后的最大二进制串
给定仅含 '0' 和 '1' 的二进制串,允许以下操作:(1) 将子串 "00" 替换为 "10";(2) 将子串 "10" 替换为 "01"。求能得到的最大二进制串。
示例:
输入:binary = "000110" 输出:"111011"
输入:binary = "01" 输出:"01"
关键观察:所有零最终可汇聚为一个零,其位置由首个零之后的 1 的数量决定。该零应放在首个零后连续 1 的末尾处。
class Solution {
public:
string maximumBinaryString(string binary) {
int len = binary.size();
int onesAfterFirstZero = 0;
bool hasZero = false;
for (char ch : binary) {
if (ch == '0') hasZero = true;
else if (hasZero) onesAfterFirstZero++;
}
if (!hasZero) return binary;
string result(len, '1');
result[len - 1 - onesAfterFirstZero] = '0';
return result;
}
};
1704. 字符串两半相似性
标签:基础题
1705. 最多吃掉的苹果数
标签:优先队列
1724. 边长限制下的路径可达性 II
标签:并查集
1732. 最高海拔
标签:基础题
1735. 乘积数组方案数
标签:组合数学
1738. 第 K 大异或坐标值
给定 m×n 非负整数矩阵,坐标 (r,c) 的值为左上角子矩阵所有元素的异或。求所有坐标值中第 K 大的值。
示例:
输入:matrix = [[5,2],[1,6]], k = 1 输出:7
输入:matrix = [[5,2],[1,6]], k = 2 输出:5
利用二维异或前缀和,然后用 nth_element 快速选择第 K 大:
class Solution {
public:
int kthLargestValue(vector<vector<int>>& mat, int k) {
int rows = mat.size(), cols = mat[0].size();
vector<int> xors;
xors.reserve(rows * cols);
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (r > 0) mat[r][c] ^= mat[r - 1][c];
if (c > 0) mat[r][c] ^= mat[r][c - 1];
if (r > 0 && c > 0) mat[r][c] ^= mat[r - 1][c - 1];
xors.push_back(mat[r][c]);
}
}
nth_element(xors.begin(), xors.begin() + k - 1, xors.end(), greater<int>());
return xors[k - 1];
}
};
1740. 二叉树中两节点距离
标签:二叉树
1742. 盒中小球的最大数量
标签:基础题
1752. 数组排序与轮转检查
标签:基础题
1753. 移除石子的最大得分
有三堆石子,大小分别为 a、b、c。每回合从两个不同的非空堆各取一颗石子得 1 分,当有两个或更多空堆时停止。求最大分数。
示例:
输入:a = 2, b = 4, c = 6 输出:6
输入:a = 4, b = 4, c = 6 输出:7
输入:a = 1, b = 8, c = 8 输出:8
若最大堆 ≥ 其余两堆之和,则答案为两小堆之和;否则答案为总数的一半(向下取整)。
class Solution {
public:
int maximumScore(int a, int b, int c) {
vector<int> piles = {a, b, c};
sort(piles.begin(), piles.end());
int biggest = piles[2];
int rest = piles[0] + piles[1];
if (biggest >= rest) return rest;
return (a + b + c) / 2;
}
};
1766. 互质树
标签:动态规划
1768. 交替合并字符串
标签:基础题
1773. 按规则匹配的物品计数
每件物品有类型、颜色、名称三个属性。给定规则键 ruleKey 和规则值 ruleValue,统计匹配的物品数。
示例:
输入:items = [["phone","blue","pixel"],["computer","silver","lenovo"],["phone","gold","iphone"]], ruleKey = "color", ruleValue = "silver" 输出:1
输入:items = [["phone","blue","pixel"],["computer","silver","phone"],["phone","gold","iphone"]], ruleKey = "type", ruleValue = "phone" 输出:2
class Solution {
public:
int countMatches(vector<vector<string>>& items, string ruleKey, string ruleValue) {
int col = (ruleKey == "type") ? 0 : (ruleKey == "color") ? 1 : 2;
int cnt = 0;
for (const auto& item : items)
if (item[col] == ruleValue) cnt++;
return cnt;
}
};
1780. 三的幂和表示判定
标签:数论
1785. 达到目标和的最少元素
给定数组 nums、上限 limit 和目标 goal,每个元素绝对值不超过 limit。求最少需要添加多少个绝对值不超过 limit 的元素使总和等于 goal。
示例:
输入:nums = [1,-1,1], limit = 3, goal = -4 输出:2
输入:nums = [1,-10,9,1], limit = 100, goal = 0 输出:1
class Solution {
public:
int minElements(vector<int>& nums, int limit, int goal) {
long long total = 0;
for (int x : nums) total += x;
long long diff = abs(total - goal);
return (diff + limit - 1) / limit;
}
};
1793. 好子数组的最大分数
标签:双指针
1796. 字符串中第二大的数字
标签:基础题
1799. N 次操作后的最大得分
标签:状态压缩动态规划
1801. 积压订单总数
订单数组 orders[i] = [price, amount, type],type=0 为采购、type=1 为销售。采购单与积压中最低价销售单匹配(采购价 ≥ 销售价),反之同理。返回最终积压订单总数对 1e9+7 取余。
示例:
输入:orders = [[10,5,0],[15,2,1],[25,1,1],[30,4,0]] 输出:6
输入:orders = [[7,1000000000,1],[15,3,0],[5,999999995,0],[5,1,1]] 输出:999999984
使用两个有序映射分别维护采购和销售积压:
class Solution {
public:
int getNumberOfBacklogOrders(vector<vector<int>>& orders) {
const int MOD = 1e9 + 7;
long long total = 0;
map<int, long long> buys, sells;
for (auto& o : orders) {
int price = o[0], amt = o[1], type = o[2];
total += amt;
if (type == 0) {
while (amt > 0 && !sells.empty() && sells.begin()->first <= price) {
auto it = sells.begin();
long long matched = min((long long)amt, it->second);
amt -= matched;
it->second -= matched;
total -= 2 * matched;
if (it->second == 0) sells.erase(it);
}
if (amt > 0) buys[price] += amt;
} else {
while (amt > 0 && !buys.empty() && buys.rbegin()->first >= price) {
auto it = prev(buys.end());
long long matched = min((long long)amt, it->second);
amt -= matched;
it->second -= matched;
total -= 2 * matched;
if (it->second == 0) buys.erase(it);
}
if (amt > 0) sells[price] += amt;
}
}
return ((total % MOD) + MOD) % MOD;
}
};
1802. 有界数组指定下标最大值
标签:二分查找
1803. 异或值在范围内的数对计数
标签:字典树
1804. 前缀树实现 II
标签:前缀树
1805. 字符串中不同整数计数
标签:基础题
1806. 还原排列的最少步数
标签:群论
1807. 替换字符串中的括号内容
标签:基础题
1808. 好因子的最大数目
标签:调整法
1812. 棋盘格子颜色判定
给定国际象棋棋盘坐标(如 "a1"),白色返回 true,黑色返回 false。

示例:
输入:coordinates = "a1" 输出:false
输入:coordinates = "h3" 输出:true
class Solution {
public:
bool squareIsWhite(string coord) {
int col = coord[0] - 'a';
int row = coord[1] - '1';
return (col + row) % 2 == 1;
}
};
1813. 句子相似性 III
标签:基础题
1814. 好对子计数
标签:基础题
1815. 新鲜甜甜圈最多组数
标签:模拟退火
1817. 用户活跃分钟数
给定用户操作日志 logs[i] = [ID, time],用户活跃分钟数 UAM 为该用户执行操作的不同分钟数。统计 UAM 分布:answer[j] 表示 UAM 等于 j 的用户数。
示例:
输入:logs = [[0,5],[1,2],[0,2],[0,5],[1,3]], k = 5 输出:[0,2,0,0,0]
输入:logs = [[1,1],[2,2],[2,3]], k = 4 输出:[1,1,0,0]
class Solution {
public:
vector<int> findingUsersActiveMinutes(vector<vector<int>>& logs, int k) {
unordered_map<int, unordered_set<int>> userTimes;
for (auto& log : logs)
userTimes[log[0]].insert(log[1]);
vector<int> result(k, 0);
for (auto& [uid, times] : userTimes) {
int uam = times.size();
if (uam >= 1 && uam <= k)
result[uam - 1]++;
}
return result;
}
};
1819. 序列中不同最大公约数计数
标签:欧几里得算法
1822. 数组元素积的符号
定义 signFunc(x):正数返回 1,负数返回 -1,零返回 0。求数组所有元素乘积的符号函数值。
示例:
输入:nums = [-1,-2,-3,-4,3,2,1] 输出:1
输入:nums = [1,5,0,2,-3] 输出:0
输入:nums = [-1,1,-1,1,-1] 输出:-1
class Solution {
public:
int arraySign(vector<int>& nums) {
int negCount = 0;
for (int x : nums) {
if (x == 0) return 0;
if (x < 0) negCount++;
}
return (negCount % 2 == 0) ? 1 : -1;
}
};
1823. 游戏获胜者
标签:约瑟夫问题
1824. 最少侧跳次数
3 跑道道路上青蛙从第 2 跑道出发,每个点最多一个障碍。青蛙可沿跑道前进或侧跳到无障碍的跑道。求到达终点的最少侧跳次数。
示例:
输入:obstacles = [0,1,2,3,0] 输出:2
输入:obstacles = [0,1,1,3,3,0] 输出:0
输入:obstacles = [0,2,1,0,3,0] 输出:2
动态规划:dp[lane] 表示到达当前位置各跑道的最少侧跳次数,逐点转移。
class Solution {
public:
int minSideJumps(vector<int>& obstacles) {
int n = obstacles.size();
vector<int> dp = {1, 0, 1}; // lane 0,1,2
for (int i = 1; i < n; i++) {
for (int lane = 0; lane < 3; lane++) {
if (obstacles[i] == lane + 1) dp[lane] = INT_MAX;
}
for (int lane = 0; lane < 3; lane++) {
if (obstacles[i] == lane + 1) continue;
for (int other = 0; other < 3; other++) {
if (obstacles[i] == other + 1) continue;
dp[lane] = min(dp[lane], dp[other] + 1);
}
}
}
return min(dp[0], min(dp[1], dp[2]));
}
};
1825. MK 平均值
维护数据流,计算最后 m 个元素去掉最小 k 个和最大 k 个后的平均值(向下取整)。
示例:
输入:["MKAverage","addElement","addElement","calculateMKAverage","addElement","calculateMKAverage","addElement","addElement","addElement","calculateMKAverage"]
[[3,1],[3],[1],[],[10],[],[5],[5],[5],[]]
输出:[null,null,null,-1,null,3,null,null,null,5]
使用三个 multiset 分别维护最小 k 个、中间 m-2k 个、最大 k 个元素,配合队列维护滑动窗口。
class MKAverage {
int windowSize, trimCount;
queue<int> dataQueue;
multiset<int> lower, middle, upper;
long long middleSum = 0;
public:
MKAverage(int m, int k) : windowSize(m), trimCount(k) {}
void addElement(int num) {
if ((int)dataQueue.size() < windowSize - 1) {
dataQueue.push(num);
return;
}
if ((int)dataQueue.size() == windowSize - 1) {
dataQueue.push(num);
vector<int> tmp;
queue<int> cq = dataQueue;
while (!cq.empty()) { tmp.push_back(cq.front()); cq.pop(); }
sort(tmp.begin(), tmp.end());
for (int i = 0; i < trimCount; i++) lower.insert(tmp[i]);
for (int i = trimCount; i < windowSize - trimCount; i++) {
middle.insert(tmp[i]);
middleSum += tmp[i];
}
for (int i = windowSize - trimCount; i < windowSize; i++) upper.insert(tmp[i]);
return;
}
int oldest = dataQueue.front();
dataQueue.pop();
removeVal(oldest);
dataQueue.push(num);
insertVal(num);
}
int calculateMKAverage() {
if ((int)dataQueue.size() < windowSize) return -1;
return middleSum / (windowSize - 2 * trimCount);
}
private:
void removeVal(int v) {
int origin;
if (v < *middle.begin()) { lower.erase(lower.find(v)); origin = 1; }
else if (v < *upper.begin()) { middle.erase(middle.find(v)); middleSum -= v; origin = 2; }
else { upper.erase(upper.find(v)); origin = 3; }
if (origin <= 2) {
int x = *upper.begin();
middle.insert(x); middleSum += x;
upper.erase(upper.begin());
}
if (origin <= 1) {
int x = *middle.begin();
lower.insert(x); middleSum -= x;
middle.erase(middle.begin());
}
}
void insertVal(int v) {
lower.insert(v);
int x = *lower.rbegin();
middle.insert(x); middleSum += x;
lower.erase(prev(lower.end()));
x = *middle.rbegin();
upper.insert(x); middleSum -= x;
middle.erase(prev(middle.end()));
}
};
1827. 数组递增的最少操作
每次操作可将一个元素加 1,求使数组严格递增的最少操作次数。
示例:
输入:nums = [1,1,1] 输出:3
输入:nums = [1,5,2,4,1] 输出:14
输入:nums = [8] 输出:0
class Solution {
public:
int minOperations(vector<int>& nums) {
int ops = 0;
for (int i = 1; i < (int)nums.size(); i++) {
if (nums[i] <= nums[i - 1]) {
int diff = nums[i - 1] - nums[i] + 1;
ops += diff;
nums[i] += diff;
}
}
return ops;
}
};
1828. 圆内点计数
标签:基础题
1830. 字符串有序的最少操作
标签:字典序排列
1835. 所有数对按位与的异或和
标签:贡献法
1848. 目标元素最小距离
给定数组 nums、目标值 target 和起始下标 start,找满足 nums[i] == target 且 abs(i - start) 最小的下标,返回该绝对值。
示例:
输入:nums = [1,2,3,4,5], target = 5, start = 3 输出:1
输入:nums = [1], target = 1, start = 0 输出:0
输入:nums = [1,1,1,1,1,1,1,1,1,1], target = 1, start = 0 输出:0
class Solution {
public:
int getMinDistance(vector<int>& nums, int target, int start) {
int best = INT_MAX;
for (int i = 0; i < (int)nums.size(); i++) {
if (nums[i] == target)
best = min(best, abs(i - start));
}
return best;
}
};
1852. 子数组数字种类数
给定数组 nums 和窗口长度 k,求每个长度为 k 的子数组中不同数字的个数。
示例:
输入:nums = [1,2,3,2,2,1,3], k = 3 输出:[3,2,2,2,3]
输入:nums = [1,1,1,1,2,3,4], k = 4 输出:[1,2,3,4]
滑动窗口配合哈希表统计频次:
class Solution {
public:
vector<int> distinctNumbers(vector<int>& nums, int k) {
unordered_map<int, int> freq;
int distinct = 0;
vector<int> result;
for (int i = 0; i < (int)nums.size(); i++) {
if (freq[nums[i]] == 0) distinct++;
freq[nums[i]]++;
if (i >= k) {
freq[nums[i - k]]--;
if (freq[nums[i - k]] == 0) distinct--;
}
if (i >= k - 1) result.push_back(distinct);
}
return result;
}
};
1861. 旋转盒子
标签:双指针
1862. 向下取整的数对和
标签:数论
1863. 子集异或总和求和
标签:贡献法
1866. 恰好 K 根木棍可见的排列数
标签:组合数学
1871. 跳跃游戏 VII
标签:广度优先搜索
1872. 石子游戏 VIII
标签:博弈论
1874. 两数组最小乘积和
给定两个等长数组 nums1 和 nums2,可任意重排 nums1,求最小乘积和。
示例:
输入:nums1 = [5,3,4,2], nums2 = [4,2,2,5] 输出:40
输入:nums1 = [2,1,4,5,7], nums2 = [3,2,4,8,6] 输出:65
排序后交叉配对(升序 × 降序)可得最小乘积和。
class Solution {
public:
int minProductSum(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.rbegin(), nums2.rend());
int total = 0;
for (int i = 0; i < (int)nums1.size(); i++)
total += nums1[i] * nums2[i];
return total;
}
};
1883. 准时到达的最小跳过休息次数
标签:二维动态规划
1884. 两枚鸡蛋掉落
标签:决策优化
1885. 数对统计
标签:双指针
1901. 二维峰值查找
标签:二分查找
1902. 由插入顺序求二叉搜索树深度
标签:平衡搜索树
1908. Nim 游戏 II
标签:博弈论
1911. 最大交替子序列和
标签:数列动态规划
1916. 蚁群筑房顺序统计
标签:组合数学
1922. 好数字计数
标签:快速幂
1927. 求和博弈
标签:博弈论
1944. 队列中可见人数
标签:单调栈
1953. 最大工作周数
标签:贪心算法
1954. 收集足够苹果的最小周长
标签:基础题
1969. 最小非零乘积
标签:快速幂
1971. 图中路径存在性
标签:广度优先搜索
1973. 值等于子节点和的节点
标签:二叉树
1976. 到达目的地方案数
标签:最短路径
1979. 数组最大公约数
标签:欧几里得算法
1982. 从子集和还原数组
标签:组合问题
1985. 数组中第 K 大整数
给定字符串数组 nums,每个字符串表示一个无前导零的非负整数,返回第 K 大的整数字符串。重复数字视为不同元素。
示例:
输入:nums = ["3","6","7","10"], k = 4 输出:"3"
输入:nums = ["2","21","12","1"], k = 3 输出:"2"
输入:nums = ["0","0"], k = 2 输出:"0"
按字符串长度为第一关键字、字典序为第二关键字排序:
class Solution {
public:
string kthLargestNumber(vector<string>& nums, int k) {
auto cmp = [](const string& a, const string& b) {
if (a.size() != b.size()) return a.size() < b.size();
return a < b;
};
sort(nums.begin(), nums.end(), cmp);
return nums[nums.size() - k];
}
};
1989. 捉迷藏可捕获最大人数
标签:多指针
1992. 农场组查找
标签:并查集
1997. 访问完所有房间的第一天
标签:数列动态规划
1998. 数组最大公因数排序
标签:因式分解
1999. 仅由两个数字组成的最小倍数
给定整数 k 和两个数字 digit1、digit2,求大于 k 且仅由这两个数字组成的 k 的最小倍数。若不存在或超出 32 位整数范围返回 -1。
示例:
输入:k = 2, digit1 = 0, digit2 = 2 输出:20
输入:k = 3, digit1 = 4, digit2 = 2 输出:24
输入:k = 2, digit1 = 0, digit2 = 0 输出:-1
使用 BFS 按数字位数递增顺序搜索,优先尝试较小的数字:
class Solution {
public:
int findInteger(int k, int d1, int d2) {
if (d1 > d2) swap(d1, d2);
queue<long long> q;
q.push(0);
while (!q.empty()) {
long long cur = q.front();
q.pop();
for (int d : {d1, d2}) {
long long nxt = cur * 10 + d;
if (nxt > INT_MAX) continue;
if (nxt == 0) continue;
if (nxt > k && nxt % k == 0) return (int)nxt;
q.push(nxt);
}
}
return -1;
}
};