前言

目前,打算不在更新(2024-4-10)。

自己的 LeetCode 刷题记录.

LeetCode 官网: https://leetcode.cn/

我一共刷了150+236+12=398道题:简单题(150),中等题(236),困难题(12)。

操作系统:Windows 10 专业版

简单

面试题 05.07. 配对交换

问题地址:https://leetcode.cn/problems/exchange-lcci/

配对交换。编写程序,交换某个整数的奇数位和偶数位,尽量使用较少的指令(也就是说,位0与位1交换,位2与位3交换,以此类推)。

1
2
3
4
5
6
class Solution {
public:
int exchangeBits(int num) {
return ((num & 0xaaaaaaaa) >> 1) | ((num & 0x55555555) << 1);
}
};

剑指 Offer 57. 和为s的两个数字

问题地址:https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans;
int left = 0 , right = nums.size()-1;
while(left<right)
{
if(nums[left] + nums[right] < target) left++;
else if(nums[left] + nums[right] > target) right--;
else
{
ans.push_back(nums[left]);
ans.push_back(nums[right]);
break;
}
}
return ans;
}
};

1114. 按序打印

问题地址:https://leetcode.cn/problems/print-in-order/

给你一个类:

1
2
3
4
5
public class Foo {
  public void first() { print("first"); }
  public void second() { print("second"); }
  public void third() { print("third"); }
}

三个不同的线程 A、B、C 将会共用一个 Foo 实例。

  • 线程 A 将会调用 first() 方法
  • 线程 B 将会调用 second() 方法
  • 线程 C 将会调用 third() 方法

请设计修改程序,以确保 second() 方法在 first() 方法之后被执行,third() 方法在 second() 方法之后被执行。

提示:

  • 尽管输入中的数字似乎暗示了顺序,但是我们并不保证线程在操作系统中的调度顺序。
  • 你看到的输入格式主要是为了确保测试的全面性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Foo {
condition_variable cv;
mutex mtx;
int k = 0;
public:
void first(function<void()> printFirst) {
printFirst();
k = 1;
cv.notify_all(); // 通知其他所有在等待唤醒队列中的线程
}

void second(function<void()> printSecond) {
unique_lock<mutex> lock(mtx); // lock mtx
cv.wait(lock, [this](){ return k == 1; }); // unlock mtx,并阻塞等待唤醒通知,需要满足 k == 1 才能继续运行
printSecond();
k = 2;
cv.notify_one(); // 随机通知一个(unspecified)在等待唤醒队列中的线程
}

void third(function<void()> printThird) {
unique_lock<mutex> lock(mtx); // lock mtx
cv.wait(lock, [this](){ return k == 2; }); // unlock mtx,并阻塞等待唤醒通知,需要满足 k == 2 才能继续运行
printThird();
}
};

1629. 按键持续时间最长的键

问题地址:https://leetcode.cn/problems/slowest-key/

LeetCode 设计了一款新式键盘,正在测试其可用性。测试人员将会点击一系列键(总计 n 个),每次一个。

给你一个长度为 n 的字符串 keysPressed ,其中 keysPressed[i] 表示测试序列中第 i 个被按下的键。releaseTimes 是一个升序排列的列表,其中 releaseTimes[i] 表示松开第 i 个键的时间。字符串和数组的 下标都从 0 开始 。第 0 个键在时间为 0 时被按下,接下来每个键都 恰好 在前一个键松开时被按下。

测试人员想要找出按键 持续时间最长 的键。第 i 次按键的持续时间为 releaseTimes[i] - releaseTimes[i - 1] ,第 0 次按键的持续时间为 releaseTimes[0]

注意,测试期间,同一个键可以在不同时刻被多次按下,而每次的持续时间都可能不同。

请返回单次按键 持续时间最长 的键,如果有多个这样的键,则返回 按字母顺序排列最大 的那个键。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
char slowestKey(vector<int>& releaseTimes, string keysPressed) {
int n = releaseTimes.size();
char ans = keysPressed[0];
int maxTime = releaseTimes[0];
for (int i = 1; i < n; i++) {
char key = keysPressed[i];
int time = releaseTimes[i] - releaseTimes[i - 1];
if (time > maxTime || (time == maxTime && key > ans)) {
ans = key;
maxTime = time;
}
}
return ans;
}
};

704. 二分查找

问题地址:https://leetcode.cn/problems/binary-search/

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right) {
int mid = (right - left) / 2 + left;
int num = nums[mid];
if (num == target) {
return mid;
} else if (num > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
};

2496. 数组中字符串的最大值

问题地址:https://leetcode.cn/problems/maximum-value-of-a-string-in-an-array/

一个由字母和数字组成的字符串的  定义如下:

  • 如果字符串 包含数字,那么值为该字符串在 10 进制下的所表示的数字。
  • 否则,值为字符串的 长度 。

给你一个字符串数组 strs ,每个字符串都只由字母和数字组成,请你返回 strs 中字符串的 最大值 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int maximumValue(vector<string>& strs) {
int res = 0;
for (auto& s : strs) {
bool isDigits = true;
for (auto& c : s) {
isDigits &= isdigit(c);
}
res = max(res, isDigits ? stoi(s) : (int)s.size());
}
return res;
}
};

709. 转换成小写字母

问题地址:https://leetcode.cn/problems/to-lower-case/

给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。

1
2
3
4
5
6
7
8
9
class Solution {
public:
string toLowerCase(string s) {
for (char& ch: s) {
ch = tolower(ch);
}
return s;
}
};

747. 至少是其他数字两倍的最大数

问题地址:https://leetcode.cn/problems/largest-number-at-least-twice-of-others/

给你一个整数数组 nums ,其中总是存在 唯一的 一个最大整数 。

请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int dominantIndex(vector<int>& nums) {
int m1 = -1, m2 = -1;
int index = -1;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > m1) {
m2 = m1;
m1 = nums[i];
index = i;
} else if (nums[i] > m2) {
m2 = nums[i];
}
}
return m1 >= m2 * 2 ? index : -1;
}
};

面试题 16.15. 珠玑妙算

问题地址:https://leetcode.cn/problems/master-mind-lcci/

珠玑妙算游戏(the game of master mind)的玩法如下。

计算机有4个槽,每个槽放一个球,颜色可能是红色(R)、黄色(Y)、绿色(G)或蓝色(B)。例如,计算机可能有RGGB 4种(槽1为红色,槽2、3为绿色,槽4为蓝色)。作为用户,你试图猜出颜色组合。打个比方,你可能会猜YRGB。要是猜对某个槽的颜色,则算一次“猜中”;要是只猜对颜色但槽位猜错了,则算一次“伪猜中”。注意,“猜中”不能算入“伪猜中”。

给定一种颜色组合solution和一个猜测guess,编写一个方法,返回猜中和伪猜中的次数answer,其中answer[0]为猜中的次数,answer[1]为伪猜中的次数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
vector<int> masterMind(string solution, string guess) {
int num1 = 0, num2 = 0;
unordered_map<char, int> alpha_map;
for (char ch : solution) {
alpha_map[ch]++;
}
for (int i = 0; i < guess.size(); i++) {
if (solution[i] == guess[i]) {
num1++;
}
if (alpha_map[guess[i]]) {
alpha_map[guess[i]]--;
num2++;
}
}
return {num1, num2 - num1};
}
};

653. 两数之和 IV - 输入二叉搜索树

问题地址:https://leetcode.cn/problems/two-sum-iv-input-is-a-bst/

给定一个二叉搜索树 root 和一个目标结果 k,如果二叉搜索树中存在两个元素且它们的和等于给定的目标结果,则返回 true。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
unordered_set<int> hashTable;

bool findTarget(TreeNode *root, int k) {
if (root == nullptr) {
return false;
}
if (hashTable.count(k - root->val)) {
return true;
}
hashTable.insert(root->val);
return findTarget(root->left, k) || findTarget(root->right, k);
}
};

1413. 逐步求和得到正数的最小值

问题地址:https://leetcode.cn/problems/minimum-value-to-get-positive-step-by-step-sum/

给你一个整数数组 nums 。你可以选定任意的 正数 startValue 作为初始值。

你需要从左到右遍历 nums 数组,并将 startValue 依次累加上 nums 数组中的值。

请你在确保累加和始终大于等于 1 的前提下,选出一个最小的 正数 作为 startValue

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int minStartValue(vector<int>& nums) {
int accSum = 0, accSumMin = 0;
for (int num : nums) {
accSum += num;
accSumMin = min(accSumMin, accSum);
}
return -accSumMin + 1;
}
};

1608. 特殊数组的特征值

问题地址:https://leetcode.cn/problems/special-array-with-x-elements-greater-than-or-equal-x/

给你一个非负整数数组 nums 。如果存在一个数 x ,使得 nums 中恰好有 x 个元素 大于或者等于 x ,那么就称 nums 是一个 特殊数组 ,而 x 是该数组的 特征值 。

注意: x 不必 是 nums 的中的元素。

如果数组 nums 是一个 特殊数组 ,请返回它的特征值 x 。否则,返回 -1 。可以证明的是,如果 nums 是特殊数组,那么其特征值 x 是 唯一的 。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int specialArray(vector<int>& nums) {
sort(nums.begin(), nums.end(), greater<int>());
int n = nums.size();
for (int i = 1; i <= n; ++i) {
if (nums[i - 1] >= i && (i == n || nums[i] < i)) {
return i;
}
}
return -1;
}
};

LCP 17. 速算机器人

问题地址:https://leetcode.cn/problems/nGK0Fy/

小扣在秋日市集发现了一款速算机器人。店家对机器人说出两个数字(记作 x 和 y),请小扣说出计算指令:

  • “A” 运算:使 x = 2 * x + y;
  • “B” 运算:使 y = 2 * y + x。

在本次游戏中,店家说出的数字为 x = 1 和 y = 0,小扣说出的计算指令记作仅由大写字母 A、B 组成的字符串 s,字符串中字符的顺序表示计算顺序,请返回最终 x 与 y 的和为多少。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int funa(int x, int y) {
return 2 * x + y;
}
int funb(int x, int y) {
return 2 * y + x;
}
int calculate(string s) {
int x = 1;
int y = 0;
for (char c : s) {
if (c == 'A') {
x = funa(x, y);
} else {
y = funb(x, y);
}
}
return x + y;
}
};

1502. 判断能否形成等差数列

问题地址:https://leetcode.cn/problems/can-make-arithmetic-progression-from-sequence/

给你一个数字数组 arr

如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为 等差数列

如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
bool canMakeArithmeticProgression(vector<int>& arr) {
sort(arr.begin(), arr.end());
for (int i = 1; i < arr.size() - 1; ++i) {
if (arr[i] * 2 != arr[i - 1] + arr[i + 1]) {
return false;
}
}
return true;
}
};

1013. 将数组分成和相等的三个部分

问题地址:https://leetcode.cn/problems/partition-array-into-three-parts-with-equal-sum/

给你一个整数数组 arr,只有可以将其划分为三个和相等的 非空 部分时才返回 true,否则返回 false。

形式上,如果可以找出索引 i + 1 < j 且满足 (arr[0] + arr[1] + ... + arr[i] == arr[i + 1] + arr[i + 2] + ... + arr[j - 1] == arr[j] + arr[j + 1] + ... + arr[arr.length - 1]) 就可以将数组三等分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
bool canThreePartsEqualSum(vector<int>& arr) {
int s = accumulate(arr.begin(), arr.end(), 0);
if (s % 3 != 0) {
return false;
}
int target = s / 3;
int n = arr.size(), i = 0, cur = 0;
while (i < n) {
cur += arr[i];
if (cur == target) {
break;
}
++i;
}
if (cur != target) {
return false;
}
int j = i + 1;
while (j + 1 < n) { // 需要满足最后一个数组元素非空
cur += arr[j];
if (cur == target * 2) {
return true;
}
++j;
}
return false;
}
};

面试题 03.01. 三合一

问题地址:https://leetcode.cn/problems/three-in-one-lcci/

三合一。描述如何只用一个数组来实现三个栈。

你应该实现push(stackNum, value)、pop(stackNum)、isEmpty(stackNum)、peek(stackNum)方法。stackNum表示栈下标,value表示压入的值。

构造函数会传入一个stackSize参数,代表每个栈的大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class TripleInOne {
public:
TripleInOne(int stackSize) {
this->stackSize = stackSize;
arr.resize(3 * stackSize);
ptrs.resize(3);
ptrs[0] = 0;
ptrs[1] = stackSize;
ptrs[2] = stackSize * 2;
}

void push(int stackNum, int value) {
if (ptrs[stackNum] < (stackNum + 1) * stackSize) {
arr[ptrs[stackNum]] = value;
ptrs[stackNum]++;
}
}

int pop(int stackNum) {
if (isEmpty(stackNum)) return -1;
ptrs[stackNum]--;
return arr[ptrs[stackNum]];
}

int peek(int stackNum) {
if (isEmpty(stackNum)) return -1;
return arr[ptrs[stackNum] - 1];
}

bool isEmpty(int stackNum) {
return ptrs[stackNum] == stackSize * stackNum;
}

private:
vector<int> arr;
vector<int> ptrs;
int stackSize;
};

/**
* Your TripleInOne object will be instantiated and called as such:
* TripleInOne* obj = new TripleInOne(stackSize);
* obj->push(stackNum,value);
* int param_2 = obj->pop(stackNum);
* int param_3 = obj->peek(stackNum);
* bool param_4 = obj->isEmpty(stackNum);
*/

LCR 023. 相交链表

问题地址:https://leetcode.cn/problems/3u1WK4/

给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode *> visited;
ListNode * temp = headA;
while (temp != nullptr) {
visited.insert(temp);
temp = temp->next;
}
temp = headB;
while (temp != nullptr) {
if (visited.count(temp)) {
return temp;
}
temp = temp->next;
}
return nullptr;
}
};

1544. 整理字符串

问题地址:https://leetcode.cn/problems/make-the-string-great/

给你一个由大小写英文字母组成的字符串 s

一个整理好的字符串中,两个相邻字符 s[i]s[i+1],其中 0<= i <= s.length-2 ,要满足如下条件:

  • s[i] 是小写字符,则 s[i+1] 不可以是相同的大写字符。
  • s[i] 是大写字符,则 s[i+1] 不可以是相同的小写字符。

请你将字符串整理好,每次你都可以从字符串中选出满足上述条件的 两个相邻 字符并删除,直到字符串整理好为止。

请返回整理好的 字符串 。题目保证在给出的约束条件下,测试样例对应的答案是唯一的。

注意:空字符串也属于整理好的字符串,尽管其中没有任何字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
string makeGood(string s) {
string ret;
for (char ch : s) {
if (!ret.empty() && tolower(ret.back()) == tolower(ch) && ret.back() != ch) {
ret.pop_back();
} else {
ret.push_back(ch);
}
}
return ret;
}
};

9. 回文数

问题地址:https://leetcode.cn/problems/palindrome-number/

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

  • 例如,121 是回文,而 123 不是。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
bool isPalindrome(int x) {
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}

int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
return x == revertedNumber || x == revertedNumber / 10;
}
};

14. 最长公共前缀

问题地址:https://leetcode.cn/problems/longest-common-prefix/

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (!strs.size()) {
return "";
}
int length = strs[0].size();
int count = strs.size();
for (int i = 0; i < length; i++) {
char c = strs[0][i];
for (int j = 1; j < count; ++j) {
if (i == strs[j].size() || strs[j][i] != c) {
return strs[0].substr(0, i);
}
}
}
return strs[0];
}
};

2490. 回环句

问题地址:https://leetcode.cn/problems/circular-sentence/

句子 是由单个空格分隔的一组单词,且不含前导或尾随空格。

  • 例如,“Hello World”、“HELLO”、“hello world hello world” 都是符合要求的句子。

单词 仅 由大写和小写英文字母组成。且大写和小写字母会视作不同字符。

如果句子满足下述全部条件,则认为它是一个 回环句 :

  • 单词的最后一个字符和下一个单词的第一个字符相等。
  • 最后一个单词的最后一个字符和第一个单词的第一个字符相等。

例如,“leetcode exercises sound delightful”、“eetcode”、“leetcode eats soul” 都是回环句。然而,“Leetcode is cool”、“happy Leetcode”、“Leetcode” 和 “I like Leetcode” 都 不 是回环句。

给你一个字符串 sentence ,请你判断它是不是一个回环句。如果是,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
bool isCircularSentence(string sentence) {
if (sentence.back() != sentence.front()) {
return false;
}
for (int i = 0; i < sentence.size(); i++) {
if (sentence[i] == ' ' && sentence[i + 1] != sentence[i - 1]) {
return false;
}
}
return true;
}
};

20. 有效的括号

问题地址:https://leetcode.cn/problems/valid-parentheses/

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
bool isValid(string s) {
int n = s.size();
if (n % 2 == 1) {
return false;
}

unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};

stack<char> stk;
for (char ch : s) {
if (pairs.count(ch)) {
if (stk.empty() || stk.top() != pairs[ch]) {
return false;
}
stk.pop();
} else {
stk.push(ch);
}
}
return stk.empty();
}
};

27. 移除元素

问题地址:https://leetcode.cn/problems/remove-element/

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int left = 0;
for (int right = 0; right < n; right++) {
if (nums[right] != val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
};

13. 罗马数字转整数

问题地址:https://leetcode.cn/problems/roman-to-integer/

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

1
2
3
4
5
6
7
8
字符          数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给定一个罗马数字,将其转换成整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
private:
unordered_map<char, int> symbolValues = {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
public:
int romanToInt(string s) {
int ans = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
int value = symbolValues[s[i]];
if (i < n - 1 && value < symbolValues[s[i + 1]]) {
ans -= value;
} else {
ans += value;
}
}
return ans;
}
};

21. 合并两个有序链表

问题地址:https://leetcode.cn/problems/merge-two-sorted-lists/

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode * preHead = new ListNode(-1);
ListNode * prev = preHead;
while (list1 != nullptr && list2 != nullptr) {
if (list1->val < list2->val) {
prev->next = list1;
list1 = list1->next;
} else {
prev->next = list2;
list2 = list2->next;
}
prev = prev->next;
}
prev->next = list1 == nullptr ? list2 : list1;
return preHead->next;
}
};

1. 两数之和

问题地址:https://leetcode.cn/problems/two-sum/

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
auto n = nums.size();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] + nums[j] == target) {
return {i, j};
}
}
}
return {};
}
};

144. 二叉树的前序遍历

问题地址:https://leetcode.cn/problems/binary-tree-preorder-traversal/

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void preorder(TreeNode * root, vector<int> &res) {
if (root == nullptr) {
return;
}
res.push_back(root->val);
preorder(root->left, res);
preorder(root->right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
preorder(root, res);
return res;
}
};

26. 删除有序数组中的重复项

问题地址:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int fast = 1, slow = 1;
while (fast < n) {
if (nums[fast] != nums[fast - 1]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
};

2760. 最长奇偶子数组

问题地址:https://leetcode.cn/problems/longest-even-odd-subarray-with-threshold/

给你一个下标从 0 开始的整数数组 nums 和一个整数 threshold 。

请你从 nums 的子数组中找出以下标 l 开头、下标 r 结尾 (0 <= l <= r < nums.length) 且满足以下条件的 最长子数组 :

nums[l] % 2 == 0
对于范围 [l, r - 1] 内的所有下标 i ,nums[i] % 2 != nums[i + 1] % 2
对于范围 [l, r] 内的所有下标 i ,nums[i] <= threshold
以整数形式返回满足题目要求的最长子数组的长度。

注意:子数组 是数组中的一个连续非空元素序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int longestAlternatingSubarray(vector<int>& nums, int threshold) {
int ans = 0;
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] % 2 != 0) continue;
int len1 = 1;
for (int j = i; j < nums.size() - 1; ++j) {
if (nums[j] % 2 == nums[j + 1] % 2) break;
else ++len1;
}
int len2 = 0;
for (int j = i; j < nums.size(); ++j) {
if (nums[j] > threshold) break;
else ++len2;
}
ans = max(ans, min(len1, len2));
}
return ans;
}
};

28. 找出字符串中第一个匹配项的下标

问题地址:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int strStr(string haystack, string needle) {
int n = haystack.size(), m = needle.size();
for (int i = 0; i <= n - m; i++) {
int j = i, k = 0;
while (k < m and haystack[j] == needle[k]) {
j++;
k++;
}
if (k == m) return i;
}
return -1;
}
};

35. 搜索插入位置

问题地址:https://leetcode.cn/problems/search-insert-position/

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n -1, ans = n;
while (left <= right) {
int mid = ((right - left) >> 1) + left;
if (target <= nums[mid]) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
};

58. 最后一个单词的长度

问题地址:https://leetcode.cn/problems/length-of-last-word/

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。

单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int lengthOfLastWord(string s) {
int index = s.size() - 1;
while (s[index] == ' ') {
index--;
}
int wordLength = 0;
while (index >= 0 && s[index] != ' ') {
wordLength++;
index--;
}
return wordLength;
}
};

2600. K 件物品的最大和

问题地址:https://leetcode.cn/problems/k-items-with-the-maximum-sum/

袋子中装有一些物品,每个物品上都标记着数字 1 、0 或 -1 。

给你四个非负整数 numOnes 、numZeros 、numNegOnes 和 k 。

袋子最初包含:

  • numOnes 件标记为 1 的物品。
  • numZeros 件标记为 0 的物品。
  • numNegOnes 件标记为 -1 的物品。

现计划从这些物品中恰好选出 k 件物品。返回所有可行方案中,物品上所标记数字之和的最大值。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int kItemsWithMaximumSum(int numOnes, int numZeros, int numNegOnes, int k) {
if (k <= numOnes) {
return k;
} else if (k <= numOnes + numZeros) {
return numOnes;
} else {
return numOnes - (k - numOnes - numZeros);
}
}
};

66. 加一

问题地址:https://leetcode.cn/problems/plus-one/

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int n = digits.size();
for (int i = n - 1; i >= 0; --i) {
if (digits[i] != 9) {
++digits[i];
for (int j = i + 1; j < n; ++j) {
digits[j] = 0;
}
return digits;
}
}

vector<int> ans(n + 1);
ans[0] = 1;
return ans;
}
};

67. 二进制求和

问题地址:https://leetcode.cn/problems/add-binary/

给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
string addBinary(string a, string b) {
string ans;
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int n = max(a.size(), b.size()), carry = 0;
for (size_t i = 0; i < n; ++i) {
carry += i < a.size() ? (a.at(i) == '1') : 0;
carry += i < b.size() ? (b.at(i) == '1') : 0;
ans.push_back((carry % 2) ? '1' : '0');
carry /= 2;
}
if (carry) {
ans.push_back('1');
}
reverse(ans.begin(), ans.end());
return ans;
}
};

69. x 的平方根

问题地址:https://leetcode.cn/problems/sqrtx/

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

1
2
3
4
5
6
7
8
9
10
class Solution {
public:
int mySqrt(int x) {
if (x == 0) {
return 0;
}
int ans = exp(0.5 * log(x));
return ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans);
}
};

70. 爬楼梯

问题地址:https://leetcode.cn/problems/climbing-stairs/

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int climbStairs(int n) {
int p = 0, q = 0, r = 1;
for (int i = 1; i <= n; ++i) {
p = q;
q = r;
r = p + q;
}
return r;
}
};

83. 删除排序链表中的重复元素

问题地址:https://leetcode.cn/problems/remove-duplicates-from-sorted-list/

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (!head) {
return head;
}
ListNode * cur = head;
while (cur->next) {
if (cur->val == cur->next->val) {
cur->next = cur->next->next;
} else {
cur = cur->next;
}
}
return head;
}
};

88. 合并两个有序数组

问题地址:https://leetcode.cn/problems/merge-sorted-array/

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = nums1.size() - 1;
m--;
n--;
while (n >= 0) {
while (m >= 0 && nums1[m] > nums2[n]) {
swap(nums1[i--], nums1[m--]);
}
swap(nums1[i--], nums2[n--]);
}
}
};

94. 二叉树的中序遍历

问题地址:https://leetcode.cn/problems/binary-tree-inorder-traversal/

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
inorder(root, res);
return res;
}
void inorder(TreeNode* root, vector<int>& res) {
if (!root) {
return;
}
inorder(root->left, res);
res.push_back(root->val);
inorder(root->right, res);
}
};

100. 相同的树

问题地址:https://leetcode.cn/problems/same-tree/

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == nullptr && q == nullptr) {
return true;
} else if (p == nullptr || q == nullptr) {
return false;
} else if (p->val != q->val) {
return false;
} else {
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
}
};

101. 对称二叉树

问题地址:https://leetcode.cn/problems/symmetric-tree/

给你一个二叉树的根节点 root , 检查它是否轴对称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isSymmetric(TreeNode* root) {
return check(root, root);
}

bool check(TreeNode* p, TreeNode* q) {
if (!p && !q) return true;
if (!p || !q) return false;
return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
}
};

104. 二叉树的最大深度

问题地址:https://leetcode.cn/problems/maximum-depth-of-binary-tree/

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == nullptr) return 0;
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};

108. 将有序数组转换为二叉搜索树

问题地址:https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return helper(nums, 0, nums.size() - 1);
}

TreeNode* helper(vector<int>& nums, int left, int right) {
if (left > right) {
return nullptr;
}
int mid = (left + right) / 2;

TreeNode* root = new TreeNode(nums[mid]);
root->left = helper(nums, left, mid - 1);
root->right = helper(nums, mid + 1, right);
return root;
}
};

110. 平衡二叉树

问题地址:https://leetcode.cn/problems/balanced-binary-tree/

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int height(TreeNode* root) {
if (root == nullptr) {
return 0;
} else {
return max(height(root->left), height(root->right)) + 1;
}
}

bool isBalanced(TreeNode* root) {
if (root == nullptr) {
return true;
} else {
return abs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);
}
}
};

111. 二叉树的最小深度

问题地址:https://leetcode.cn/problems/minimum-depth-of-binary-tree/

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == nullptr) {
return 0;
}
if (root->left == nullptr && root->right == nullptr) {
return 1;
}
int min_depth = INT_MAX;
if (root->left != nullptr) {
min_depth = min(minDepth(root->left), min_depth);
}
if (root->right != nullptr) {
min_depth = min(minDepth(root->right), min_depth);
}
return min_depth + 1;
}
};

112. 路径总和

问题地址:https://leetcode.cn/problems/path-sum/

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
bool hasPathSum(TreeNode *root, int sum) {
if (root == nullptr) {
return false;
}
if (root->left == nullptr && root->right == nullptr) {
return sum == root->val;
}
return hasPathSum(root->left, sum - root->val) ||
hasPathSum(root->right, sum - root->val);
}
};

118. 杨辉三角

问题地址:https://leetcode.cn/problems/pascals-triangle/

给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ret(numRows);
for (int i = 0; i < numRows; ++i) {
ret[i].resize(i + 1);
ret[i][0] = ret[i][i] = 1;
for (int j = 1; j < i; ++j) {
ret[i][j] = ret[i - 1][j] + ret[i - 1][j - 1];
}
}
return ret;
}
};

119. 杨辉三角 II

问题地址:https://leetcode.cn/problems/pascals-triangle-ii/

给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<vector<int>> C(rowIndex + 1);
for (int i = 0; i <= rowIndex; ++i) {
C[i].resize(i + 1);
C[i][0] = C[i][i] = 1;
for (int j = 1; j < i; ++j) {
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
}
return C[rowIndex];
}
};

121. 买卖股票的最佳时机

问题地址:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int maxProfit(vector<int>& prices) {
int inf = 1e9;
int minPrice = inf, maxProfit = 0;
for (int price : prices) {
maxProfit = max(maxProfit, price - minPrice);
minPrice = min(price, minPrice);
}
return maxProfit;
}
};

125. 验证回文串

问题地址:https://leetcode.cn/problems/valid-palindrome/

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
bool isPalindrome(string s) {
int left = 0, right = s.length() - 1;
while (left < right) {
while (left < right && !isalnum(s[left])) {
++left;
}
while (left < right && !isalnum(s[right])) {
--right;
}
if (tolower(s[left]) != tolower(s[right])) {
return false;
}
++left;
--right;
}
return true;
}
};

136. 只出现一次的数字

问题地址:https://leetcode.cn/problems/single-number/

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

1
2
3
4
5
6
7
8
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for (auto e:nums) ret ^= e;
return ret;
}
};

141. 环形链表

问题地址:https://leetcode.cn/problems/linked-list-cycle/

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*> seen;
while (head != nullptr) {
if (seen.count(head)) {
return true;
}
seen.insert(head);
head = head->next;
}
return false;
}
};

145. 二叉树的后序遍历

问题地址:https://leetcode.cn/problems/binary-tree-postorder-traversal/

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
postorder(root, res);
return res;
}

void postorder(TreeNode *root, vector<int> &res) {
if (root == nullptr) {
return;
}
postorder(root->left, res);
postorder(root->right, res);
res.push_back(root->val);
}
};

160. 相交链表

问题地址:https://leetcode.cn/problems/intersection-of-two-linked-lists/

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode *> visited;
ListNode *temp = headA;
while (temp != nullptr) {
visited.insert(temp);
temp = temp->next;
}
temp = headB;
while (temp != nullptr) {
if (visited.count(temp)) {
return temp;
}
temp = temp->next;
}
return nullptr;
}
};

168. Excel表列名称

问题地址:https://leetcode.cn/problems/excel-sheet-column-title/

给你一个整数 columnNumber ,返回它在 Excel 表中相对应的列名称。

例如:

1
2
3
4
5
6
7
8
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28
...
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
string convertToTitle(int columnNumber) {
string ans;
while (columnNumber > 0) {
int a0 = (columnNumber - 1) % 26 + 1;
ans += a0 - 1 + 'A';
columnNumber = (columnNumber - a0) / 26;
}
reverse(ans.begin(), ans.end());
return ans;
}
};

206. 反转链表

问题地址:https://leetcode.cn/problems/reverse-linked-list/

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
};

283. 移动零

问题地址:https://leetcode.cn/problems/move-zeroes/

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int n = nums.size(), left = 0, right = 0;
while (right < n) {
if (nums[right]) {
swap(nums[left], nums[right]);
left++;
}
right++;
}
}
};

344. 反转字符串

问题地址:https://leetcode.cn/problems/reverse-string/

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

1
2
3
4
5
6
7
8
9
class Solution {
public:
void reverseString(vector<char>& s) {
int n = s.size();
for (int left = 0, right = n - 1; left < right; ++left, --right) {
swap(s[left], s[right]);
}
}
};

228. 汇总区间

问题地址:https://leetcode.cn/problems/summary-ranges/

给定一个  无重复元素 的 有序 整数数组 nums 。

返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。

列表中的每个区间范围 [a,b] 应该按如下格式输出:

  • “a->b” ,如果 a != b
  • “a” ,如果 a == b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string> ret;
int i = 0;
int n = nums.size();
while (i < n) {
int low = i;
i++;
while (i < n && nums[i] == nums[i - 1] + 1) {
i++;
}
int high = i - 1;
string temp = to_string(nums[low]);
if (low < high) {
temp.append("->");
temp.append(to_string(nums[high]));
}
ret.push_back(move(temp));
}
return ret;
}
};

169. 多数元素

问题地址:https://leetcode.cn/problems/majority-element/

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

1
2
3
4
5
6
7
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
};

171. Excel 表列序号

问题地址:https://leetcode.cn/problems/excel-sheet-column-number/

给你一个字符串 columnTitle ,表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。

例如:

1
2
3
4
5
6
7
8
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28
...
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int titleToNumber(string columnTitle) {
int number = 0;
long multiple = 1;
for (int i = columnTitle.size() - 1; i >= 0; i--) {
int k = columnTitle[i] - 'A' + 1;
number += k * multiple;
multiple *= 26;
}
return number;
}
};

190. 颠倒二进制位

问题地址:https://leetcode.cn/problems/reverse-bits/

颠倒给定的 32 位无符号整数的二进制位。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t rev = 0;
for (int i = 0; i < 32 && n > 0; ++i) {
rev |= (n & 1) << (31 - i);
n >>= 1;
}
return rev;
}
};

191. 位1的个数

问题地址:https://leetcode.cn/problems/number-of-1-bits/

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int hammingWeight(uint32_t n) {
int ret = 0;
for (int i = 0; i < 32; i++) {
if (n & (1 << i)) {
ret++;
}
}
return ret;
}
};

202. 快乐数

问题地址:https://leetcode.cn/problems/happy-number/

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
int bitSquareSum(int n) {
int sum = 0;
while(n > 0)
{
int bit = n % 10;
sum += bit * bit;
n = n / 10;
}
return sum;
}

bool isHappy(int n) {
int slow = n, fast = n;
do{
slow = bitSquareSum(slow);
fast = bitSquareSum(fast);
fast = bitSquareSum(fast);
}while(slow != fast);

return slow == 1;
}
};

203. 移除链表元素

问题地址:https://leetcode.cn/problems/remove-linked-list-elements/

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if (head == nullptr) {
return head;
}
head->next = removeElements(head->next, val);
return head->val == val ? head->next : head;
}
};

205. 同构字符串

问题地址:https://leetcode.cn/problems/isomorphic-strings/

给定两个字符串 s 和 t ,判断它们是否是同构的。

如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。

每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
bool isIsomorphic(string s, string t) {
unordered_map<char, char> s2t;
unordered_map<char, char> t2s;
int len = s.length();
for (int i = 0; i < len; ++i) {
char x = s[i], y = t[i];
if ((s2t.count(x) && s2t[x] != y) || (t2s.count(y) && t2s[y] != x)) {
return false;
}
s2t[x] = y;
t2s[y] = x;
}
return true;
}
};

217. 存在重复元素

问题地址:https://leetcode.cn/problems/contains-duplicate/

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
for (int i = 0; i < n - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
};

219. 存在重复元素 II

问题地址:https://leetcode.cn/problems/contains-duplicate-ii/

给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int, int> dict;
int len = nums.size();
for (int i = 0; i < len; i++) {
int num = nums[i];
if (dict.count(num) && i - dict[num] <= k) {
return true;
}
dict[num] = i;
}
return false;
}
};

225. 用队列实现栈

问题地址:https://leetcode.cn/problems/implement-stack-using-queues/

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class MyStack {
public:
queue<int> queue1;
queue<int> queue2;

MyStack() {

}

void push(int x) {
queue2.push(x);
while (!queue1.empty()) {
queue2.push(queue1.front());
queue1.pop();
}
swap(queue1, queue2);
}

int pop() {
int r = queue1.front();
queue1.pop();
return r;
}

int top() {
int r = queue1.front();
return r;
}

bool empty() {
return queue1.empty();
}
};

/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/

226. 翻转二叉树

问题地址:https://leetcode.cn/problems/invert-binary-tree/

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == nullptr) {
return nullptr;
}
TreeNode* left = invertTree(root->left);
TreeNode* right = invertTree(root->right);
root->left = right;
root->right = left;
return root;
}
};

231. 2 的幂

问题地址:https://leetcode.cn/problems/power-of-two/

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。

如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

1
2
3
4
5
6
class Solution {
public:
bool isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
};

232. 用栈实现队列

问题地址:https://leetcode.cn/problems/implement-queue-using-stacks/

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class MyQueue {
private:
stack<int> inStack, outStack;
void in2out() {
while (!inStack.empty()) {
outStack.push(inStack.top());
inStack.pop();
}
}
public:
MyQueue() {

}

void push(int x) {
inStack.push(x);
}

int pop() {
if (outStack.empty()) {
in2out();
}
int x = outStack.top();
outStack.pop();
return x;
}

int peek() {
if (outStack.empty()) {
in2out();
}
return outStack.top();
}

bool empty() {
return inStack.empty() && outStack.empty();
}
};

/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/

234. 回文链表

问题地址:https://leetcode.cn/problems/palindrome-linked-list/

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> vals;
while (head != nullptr) {
vals.emplace_back(head->val);
head = head->next;
}
for (int i = 0, j = vals.size() - 1; i < j; ++i, --j) {
if (vals[i] != vals[j]) {
return false;
}
}
return true;
}
};

242. 有效的字母异位词

问题地址:https://leetcode.cn/problems/valid-anagram/

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.length() != t.length()) {
return false;
}
sort(s.begin(), s.end());
sort(t.begin(), t.end());
return s == t;
}
};

392. 判断子序列

问题地址:https://leetcode.cn/problems/is-subsequence/

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
bool isSubsequence(string s, string t) {
int n = s.length(), m = t.length();
int i = 0, j = 0;
while (i < n && j < m) {
if (s[i] == t[j]) {
i++;
}
j++;
}
return i == n;
}
};

257. 二叉树的所有路径

问题地址:https://leetcode.cn/problems/binary-tree-paths/

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> paths;
construct_paths(root, "", paths);
return paths;
}
void construct_paths(TreeNode* root, string path, vector<string>& paths) {
if (root != nullptr) {
path += to_string(root->val);
if (root->left == nullptr && root->right == nullptr) {
paths.push_back(path);
} else {
path += "->";
construct_paths(root->left, path, paths);
construct_paths(root->right, path, paths);
}
}
}
};

258. 各位相加

问题地址:https://leetcode.cn/problems/add-digits/

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。返回这个结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int addDigits(int num) {
while (num >= 10) {
int sum = 0;
while (num > 0) {
sum += num % 10;
num /= 10;
}
num = sum;
}
return num;
}
};

263. 丑数

问题地址:https://leetcode.cn/problems/ugly-number/

丑数 就是只包含质因数 2、3 和 5 的正整数。

给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
bool isUgly(int n) {
if (n <= 0) {
return false;
}
vector<int> factors = {2, 3, 5};
for (auto factor : factors) {
while (n % factor == 0) {
n /= factor;
}
}
return n == 1;
}
};

268. 丢失的数字

问题地址:https://leetcode.cn/problems/missing-number/

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int missingNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
for (int i = 0; i < n; i++) {
if (nums[i] != i) {
return i;
}
}
return n;
}
};

278. 第一个错误的版本

问题地址:https://leetcode.cn/problems/first-bad-version/

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
int firstBadVersion(int n) {
int left = 1, right = n;
while (left < right) {
int mid = left + (right - left) / 2;
if (isBadVersion(mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
};

290. 单词规律

问题地址:https://leetcode.cn/problems/word-pattern/

给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。

这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
bool wordPattern(string pattern, string str) {
unordered_map<string, char> str2ch;
unordered_map<char, string> ch2str;
int m = str.length();
int i = 0;
for (auto ch : pattern) {
if (i >= m) {
return false;
}
int j = i;
while (j < m && str[j] != ' ') j++;
const string &tmp = str.substr(i, j - i);
if (str2ch.count(tmp) && str2ch[tmp] != ch) {
return false;
}
if (ch2str.count(ch) && ch2str[ch] != tmp) {
return false;
}
str2ch[tmp] = ch;
ch2str[ch] = tmp;
i = j + 1;
}
return i >= m;
}
};

292. Nim 游戏

问题地址:https://leetcode.cn/problems/nim-game/

你和你的朋友,两个人一起玩 Nim 游戏:

  • 桌子上有一堆石头。
  • 你们轮流进行自己的回合, 你作为先手 。
  • 每一回合,轮到的人拿掉 1 - 3 块石头。
  • 拿掉最后一块石头的人就是获胜者。

假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true;否则,返回 false 。

1
2
3
4
5
6
class Solution {
public:
bool canWinNim(int n) {
return n % 4 != 0;
}
};

326. 3 的幂

问题地址:https://leetcode.cn/problems/power-of-three/

给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。

整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x

1
2
3
4
5
6
7
8
9
class Solution {
public:
bool isPowerOfThree(int n) {
while (n && n % 3 == 0) {
n /= 3;
}
return n == 1;
}
};

342. 4的幂

问题地址:https://leetcode.cn/problems/power-of-four/

给定一个整数,写一个函数来判断它是否是 4 的幂次方。如果是,返回 true ;否则,返回 false 。

整数 n 是 4 的幂次方需满足:存在整数 x 使得 n == 4x

1
2
3
4
5
6
7
8
9
class Solution {
public:
bool isPowerOfFour(int n) {
while (n && n % 4 == 0) {
n /= 4;
}
return n == 1;
}
};

383. 赎金信

问题地址:https://leetcode.cn/problems/ransom-note/

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
if (ransomNote.size() > magazine.size()) {
return false;
}
vector<int> cnt(26);
for (auto & c : magazine) {
cnt[c - 'a']++;
}
for (auto & c : ransomNote) {
cnt[c - 'a']--;
if (cnt[c - 'a'] < 0) {
return false;
}
}
return true;
}
};

222. 完全二叉树的节点个数

问题地址:https://leetcode.cn/problems/count-complete-tree-nodes/

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if (!root) return 0;
return countNodes(root->left) + countNodes(root->right) + 1;
}
};

637. 二叉树的层平均值

问题地址:https://leetcode.cn/problems/average-of-levels-in-binary-tree/

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> ans;
if (!root) return ans;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
double total = 0;
int count = q.size();
int n = count;
while (count--) {
TreeNode* tmp = q.front();
q.pop();
total += tmp->val;
if (tmp->left) q.push(tmp->left);
if (tmp->right) q.push(tmp->right);
}
ans.push_back(total/n);
}
return ans;
}
};

530. 二叉搜索树的最小绝对差

问题地址:https://leetcode.cn/problems/minimum-absolute-difference-in-bst/

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

差值是一个正数,其数值等于两值之差的绝对值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int getMinimumDifference(TreeNode* root) {
int ans = INT_MAX, pre = -1;
dfs(root, pre, ans);
return ans;
}
void dfs(TreeNode* root, int& pre, int& ans) {
if (root == nullptr) return;
dfs(root->left, pre, ans);
if (pre == -1) {
pre = root->val;
} else {
ans = min(ans, root->val - pre);
pre = root->val;
}
dfs(root->right, pre, ans);
}
};

557. 反转字符串中的单词 III

问题地址:https://leetcode.cn/problems/reverse-words-in-a-string-iii/

给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
string reverseWords(string s) {
string ret;
int length = s.length();
int i = 0;
while (i < length) {
int start = i;
while (i < length && s[i] != ' ') {
i++;
}
for (int p = start; p < i; p++) {
ret.push_back(s[start + i - 1 - p]);
}
while (i < length && s[i] == ' ') {
i++;
ret.push_back(' ');
}
}
return ret;
}
};

1768. 交替合并字符串

问题地址:https://leetcode.cn/problems/merge-strings-alternately/

给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。

返回 合并后的字符串 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
string mergeAlternately(string word1, string word2) {
int m = word1.size(), n = word2.size();
int i = 0, j = 0;

string ans;
while (i < m || j < n) {
if (i < m) {
ans.push_back(word1[i]);
++i;
}
if (j < n) {
ans.push_back(word2[j]);
++j;
}
}
return ans;
}
};

1071. 字符串的最大公因子

问题地址:https://leetcode.cn/problems/greatest-common-divisor-of-strings/

对于字符串 s 和 t,只有在 s = t + … + t(t 自身连接 1 次或多次)时,我们才认定 “t 能除尽 s”。

给定两个字符串 str1 和 str2 。返回 最长字符串 x,要求满足 x 能除尽 str1 且 x 能除尽 str2 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
string gcdOfStrings(string str1, string str2) {
int len1 = str1.length(), len2 = str2.length();
for (int i = min(len1, len2); i >= 1; --i) {
if (len1 % i == 0 && len2 % i == 0) {
string x = str1.substr(0, i);
if (check(x, str1) && check(x, str2)) return x;
}
}
return "";
}
bool check(string t, string s) {
int len = s.length() / t.length();
string ans = "";
for (int i = 0; i < len; ++i) {
ans = ans + t;
}
return ans == s;
}
};

1431. 拥有最多糖果的孩子

问题地址:https://leetcode.cn/problems/kids-with-the-greatest-number-of-candies/

给你一个数组 candies 和一个整数 extraCandies ,其中 candies[i] 代表第 i 个孩子拥有的糖果数目。

对每一个孩子,检查是否存在一种方案,将额外的 extraCandies 个糖果分配给孩子们之后,此孩子有 最多 的糖果。注意,允许有多个孩子同时拥有 最多 的糖果数目。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
vector<bool> kidsWithCandies(vector<int>& candies, int extraCandies) {
int n = candies.size();
int maxCandies = *max_element(candies.begin(), candies.end());
vector<bool> ret;
for (int i = 0; i < n; ++i) {
ret.push_back(candies[i] + extraCandies >= maxCandies);
}
return ret;
}
};

605. 种花问题

问题地址:https://leetcode.cn/problems/can-place-flowers/

假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。

给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
int cnt = 0, m = flowerbed.size();
for (int i = 0; i < m; ++i) {
if ((i == 0 || flowerbed[i - 1] == 0) && flowerbed[i] == 0 && (i == m - 1 || flowerbed[i + 1] == 0)) {
cnt += 1;
flowerbed[i] = 1;
}
}
return cnt >= n;
}
};

345. 反转字符串中的元音字母

问题地址:https://leetcode.cn/problems/reverse-vowels-of-a-string/

给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。

元音字母包括 ‘a’、‘e’、‘i’、‘o’、‘u’,且可能以大小写两种形式出现不止一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
string reverseVowels(string s) {
auto isVowel = [vowels = "aeiouAEIOU"s](char ch) {
return vowels.find(ch) != string::npos;
};
int n = s.size();
int i = 0, j = n - 1;
while (i < j) {
while (i < n && !isVowel(s[i])) {
++i;
}
while (j > 0 && !isVowel(s[j])) {
--j;
}
if (i < j) {
swap(s[i], s[j]);
++i;
--j;
}
}
return s;
}
};

643. 子数组最大平均数 I

问题地址:https://leetcode.cn/problems/maximum-average-subarray-i/

给你一个由 n 个元素组成的整数数组 nums 和一个整数 k 。

请你找出平均数最大且 长度为 k 的连续子数组,并输出该最大平均数。

任何误差小于 10-5 的答案都将被视为正确答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
double findMaxAverage(vector<int>& nums, int k) {
int sum = 0;
int n = nums.size();
for (int i = 0; i < k; i++) {
sum += nums[i];
}
int maxSum = sum;
for (int i = k; i < n; i++) {
sum = sum - nums[i - k] + nums[i];
maxSum = max(maxSum, sum);
}
return static_cast<double>(maxSum) / k;
}
};

1732. 找到最高海拔

问题地址:https://leetcode.cn/problems/find-the-highest-altitude/

有一个自行车手打算进行一场公路骑行,这条路线总共由 n + 1 个不同海拔的点组成。自行车手从海拔为 0 的点 0 开始骑行。

给你一个长度为 n 的整数数组 gain ,其中 gain[i] 是点 i 和点 i + 1 的 净海拔高度差(0 <= i < n)。请你返回 最高点的海拔 。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int largestAltitude(vector<int>& gain) {
int ans = 0, sum = 0;
for (int x : gain) {
sum += x;
ans = max(ans, sum);
}
return ans;
}
};

724. 寻找数组的中心下标

问题地址:https://leetcode.cn/problems/find-pivot-index/

给你一个整数数组 nums ,请计算数组的 中心下标 。

数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。

如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int total = accumulate(nums.begin(), nums.end(), 0);
int sum = 0;
for (int i = 0; i < nums.size(); ++i) {
if (2 * sum + nums[i] == total) {
return i;
}
sum += nums[i];
}
return -1;
}
};

700. 二叉搜索树中的搜索

问题地址:https://leetcode.cn/problems/search-in-a-binary-search-tree/

给定二叉搜索树(BST)的根节点 root 和一个整数值 val。

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if (root == nullptr) return nullptr;
if (root->val == val) return root;
return searchBST(val < root->val ? root->left : root->right, val);
}
};

2215. 找出两数组的不同

问题地址:https://leetcode.cn/problems/find-the-difference-of-two-arrays/

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,请你返回一个长度为 2 的列表 answer ,其中:

  • answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整数组成的列表。
  • answer[1] 是 nums2 中所有 不 存在于 nums1 中的 不同 整数组成的列表。

注意:列表中的整数可以按 任意 顺序返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
vector<vector<int>> findDifference(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> set1, set2;
for (auto num : nums1) {
set1.insert(num);
}
for (auto num : nums2) {
set2.insert(num);
}
vector<vector<int>> res(2);
for (auto num : set1) {
if (!set2.count(num)) {
res[0].push_back(num);
}
}
for (auto num : set2) {
if (!set1.count(num)) {
res[1].push_back(num);
}
}
return res;
}
};

1207. 独一无二的出现次数

问题地址:https://leetcode.cn/problems/unique-number-of-occurrences/

给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。

如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
bool uniqueOccurrences(vector<int>& arr) {
unordered_map<int, int> occur;
for (const auto& x : arr) {
occur[x]++;
}
unordered_set<int> times;
for (const auto& x : occur) {
times.insert(x.second);
}
return times.size() == occur.size();
}
};

933. 最近的请求次数

问题地址:https://leetcode.cn/problems/number-of-recent-calls/

写一个 RecentCounter 类来计算特定时间范围内最近的请求。

请你实现 RecentCounter 类:

  • RecentCounter() 初始化计数器,请求数为 0 。
  • int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。

保证 每次对 ping 的调用都使用比之前更大的 t 值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class RecentCounter {
private:
queue<int> q;
public:
RecentCounter() {}

int ping(int t) {
q.push(t);
while ( q.front() < t - 3000) {
q.pop();
}
return q.size();
}
};

/**
* Your RecentCounter object will be instantiated and called as such:
* RecentCounter* obj = new RecentCounter();
* int param_1 = obj->ping(t);
*/

872. 叶子相似的树

问题地址:https://leetcode.cn/problems/leaf-similar-trees/

请考虑一棵二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。

举个例子,如上图所示,给定一棵叶值序列为 (6, 7, 4, 9, 8) 的树。

如果有两棵二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。

如果给定的两个根结点分别为 root1 和 root2 的树是叶相似的,则返回 true;否则返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool leafSimilar(TreeNode* root1, TreeNode* root2) {
vector<int> seq1;
if (root1) {
dfs(root1, seq1);
}
vector<int> seq2;
if (root2) {
dfs(root2, seq2);
}
return seq1 == seq2;
}
void dfs(TreeNode* node, vector<int>& seq) {
if (!node->left && !node->right) {
seq.push_back(node->val);
} else {
if (node->left) {
dfs(node->left, seq);
}
if (node->right) {
dfs(node->right, seq);
}
}
}
};

338. 比特位计数

问题地址:https://leetcode.cn/problems/counting-bits/

给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

1
2
3
4
5
6
7
8
9
10
class Solution {
public:
vector<int> countBits(int n) {
vector<int> bits(n + 1);
for (int i = 1; i <= n; i++) {
bits[i] = bits[i >> 1] + (i & 1);
}
return bits;
}
};

374. 猜数字大小

问题地址:https://leetcode.cn/problems/guess-number-higher-or-lower/

猜数字游戏的规则如下:

  • 每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
  • 如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。

你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):

  • -1:我选出的数字比你猜的数字小 pick < num
  • 1:我选出的数字比你猜的数字大 pick > num
  • 0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num

返回我选出的数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** 
* Forward declaration of guess API.
* @param num your guess
* @return -1 if num is higher than the picked number
* 1 if num is lower than the picked number
* otherwise return 0
* int guess(int num);
*/

class Solution {
public:
int guessNumber(int n) {
int left = 1, right = n;
while (left < right) {
int mid = left + (right - left) / 2;
if (guess(mid) <= 0) {
right = mid;
} else {
left = mid + 1;
}
}
return right;
}
};

1137. 第 N 个泰波那契数

问题地址:https://leetcode.cn/problems/n-th-tribonacci-number/

泰波那契序列 Tn 定义如下:

T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2

给你整数 n,请返回第 n 个泰波那契数 Tn 的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int tribonacci(int n) {
if (n == 0) {
return 0;
}
if (n <= 2) {
return 1;
}
int p = 0, q = 0, r = 1, s = 1;
for (int i = 3; i <= n; ++i) {
p = q;
q = r;
r = s;
s = p + q + r;
}
return s;
}
};

746. 使用最小花费爬楼梯

问题地址:https://leetcode.cn/problems/min-cost-climbing-stairs/

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
vector<int> dp(n + 1);
dp[0] = dp[0] = 0;
for (int i = 2; i <= n; i++) {
dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
}
return dp[n];
}
};

面试题 01.01. 判定字符是否唯一

问题地址:https://leetcode.cn/problems/is-unique-lcci/

实现一个算法,确定一个字符串 s 的所有字符是否全都不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
bool isUnique(string astr) {
int x = 0;
for (int i = 0; i < astr.size(); i++) {
if (x & (1 << (astr[i] - 'a'))) {
return false;
} else {
x |= (1 << (astr[i] - 'a'));
}
}
return true;
}
};

面试题 01.02. 判定是否互为字符重排

问题地址:https://leetcode.cn/problems/check-permutation-lcci/

给定两个由小写字母组成的字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
bool CheckPermutation(string s1, string s2) {
if (s1.length() != s2.length()) {
return false;
}
sort(s1.begin(), s1.end());
sort(s2.begin(), s2.end());
return s1 == s2;
}
};

面试题 01.03. URL化

问题地址:https://leetcode.cn/problems/string-to-url-lcci/

URL化。编写一种方法,将字符串中的空格全部替换为%20。假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的“真实”长度。(注:用Java实现的话,请使用字符数组实现,以便直接在数组上操作。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
string replaceSpaces(string S, int length) {
int idx = S.size() - 1;
for (int i = length - 1; i >= 0; i--) {
if (S[i] == ' ') {
S[idx] = '0';
S[idx - 1] = '2';
S[idx - 2] = '%';
idx -= 3;
} else {
S[idx] = S[i];
idx--;
}
}
S = S.substr(idx + 1);
return S;
}
};

面试题 01.04. 回文排列

问题地址:https://leetcode.cn/problems/palindrome-permutation-lcci/

给定一个字符串,编写一个函数判定其是否为某个回文串的排列之一。

回文串是指正反两个方向都一样的单词或短语。排列是指字母的重新排列。

回文串不一定是字典当中的单词。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
bool canPermutePalindrome(string s) {
unordered_map<char, int> dict;
for (auto c : s) {
dict[c] += 1;
}
int odd = 0;
for (auto item : dict) {
if (item.second % 2 == 1) {
if (++odd > 1) {
return false;
}
}
}
return true;
}
};

面试题 01.06. 字符串压缩

问题地址:https://leetcode.cn/problems/compress-string-lcci/

字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
string compressString(string S) {
if (S.length() == 0) return S;
string ans = "";
int cnt = 1;
char ch = S[0];
for (int i = 1; i < S.length(); ++i) {
if (ch == S[i]) cnt++;
else {
ans += ch + to_string(cnt);
ch = S[i];
cnt = 1;
}
}
ans += ch + to_string(cnt);
return ans.length() >= S.length() ? S : ans;
}
};

面试题 01.09. 字符串轮转

问题地址:https://leetcode.cn/problems/string-rotation-lcci/

字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。

1
2
3
4
5
6
class Solution {
public:
bool isFlipedString(string s1, string s2) {
return s1.size() == s2.size() && (s1 + s1).find(s2) != string::npos;
}
};

面试题 02.01. 移除重复节点

问题地址:https://leetcode.cn/problems/remove-duplicate-node-lcci/

编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeDuplicateNodes(ListNode* head) {
if (head == nullptr) {
return head;
}
unordered_set<int> occurred = {head->val};
ListNode* pos = head;
while (pos->next != nullptr) {
auto cur = pos->next;
if (!occurred.count(cur->val)) {
occurred.insert(cur->val);
pos = pos->next;
} else {
pos->next = pos->next->next;
}
}
pos->next = nullptr;
return head;
}
};

面试题 02.02. 返回倒数第 k 个节点

问题地址:https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

注意:本题相对原题稍作改动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int kthToLast(ListNode* head, int k) {
ListNode* pre = head, *cur = head;
for (int i = 0; i < k; i++) {
cur = cur->next;
}
while (cur != nullptr) {
pre = pre->next;
cur = cur->next;
}
return pre->val;
}
};

面试题 02.03. 删除中间节点

问题地址:https://leetcode.cn/problems/delete-middle-node-lcci/

若链表中的某个节点,既不是链表头节点,也不是链表尾节点,则称其为该链表的「中间节点」。

假定已知链表的某一个中间节点,请实现一种算法,将该节点从链表中删除。

例如,传入节点 c(位于单向链表 a->b->c->d->e->f 中),将其删除后,剩余链表为 a->b->d->e->f

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
};

面试题 02.06. 回文链表

问题地址:https://leetcode.cn/problems/palindrome-linked-list-lcci/

编写一个函数,检查输入的链表是否是回文的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> vals;
while (head != nullptr) {
vals.emplace_back(head->val);
head = head->next;
}
for (int i = 0, j = vals.size() - 1; i < j; ++i, --j) {
if (vals[i] != vals[j]) {
return false;
}
}
return true;
}
};

面试题 02.07. 链表相交

问题地址:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode*> visited;
ListNode* temp = headA;
while (temp != nullptr) {
visited.insert(temp);
temp = temp->next;
}
temp = headB;
while (temp != nullptr) {
if (visited.count(temp)) {
return temp;
}
temp = temp->next;
}
return nullptr;
}
};

面试题 03.02. 栈的最小值

问题地址:https://leetcode.cn/problems/min-stack-lcci/

请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class MinStack {
private:
stack<int> x_stack;
stack<int> min_stack;
public:
/** initialize your data structure here. */
MinStack() {
min_stack.push(INT_MAX);
}

void push(int x) {
x_stack.push(x);
min_stack.push(min(min_stack.top(), x));
}

void pop() {
x_stack.pop();
min_stack.pop();
}

int top() {
return x_stack.top();
}

int getMin() {
return min_stack.top();
}
};

/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(x);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/

面试题 03.04. 化栈为队

问题地址:https://leetcode.cn/problems/implement-queue-using-stacks-lcci/

实现一个MyQueue类,该类用两个栈来实现一个队列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class MyQueue {
private:
stack<int> inStack, outStack;
void in2out() {
while (!inStack.empty()) {
outStack.push(inStack.top());
inStack.pop();
}
}
public:
/** Initialize your data structure here. */
MyQueue() {}

/** Push element x to the back of queue. */
void push(int x) {
inStack.push(x);
}

/** Removes the element from in front of queue and returns that element. */
int pop() {
if (outStack.empty()) {
in2out();
}
int x = outStack.top();
outStack.pop();
return x;
}

/** Get the front element. */
int peek() {
if (outStack.empty()) {
in2out();
}
return outStack.top();
}

/** Returns whether the queue is empty. */
bool empty() {
return inStack.empty() && outStack.empty();
}
};

/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/

面试题 03.06. 动物收容所

问题地址:https://leetcode.cn/problems/animal-shelter-lcci/

动物收容所。有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时必须收养此类动物中“最老”的)。换言之,收养人不能自由挑选想收养的对象。请创建适用于这个系统的数据结构,实现各种操作方法,比如enqueue、dequeueAny、dequeueDog和dequeueCat。允许使用Java内置的LinkedList数据结构。

enqueue方法有一个animal参数,animal[0]代表动物编号,animal[1]代表动物种类,其中 0 代表猫,1 代表狗。

dequeue*方法返回一个列表[动物编号, 动物种类],若没有可以收养的动物,则返回[-1,-1]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class AnimalShelf {
public:
queue<int> cat;
queue<int> dog;
AnimalShelf() {

}

void enqueue(vector<int> animal) {
if (animal[1] == 0) cat.push(animal[0]);
else dog.push(animal[0]);
}

vector<int> dequeueAny() {
vector<int> res = {-1, -1};
if (cat.empty() && dog.empty()) return res;
if (dog.empty())
{
res = {cat.front(), 0};
cat.pop();
return res;
}
if (cat.empty())
{
res = {dog.front(), 1};
dog.pop();
return res;
}

if (cat.front() < dog.front())
{
res = {cat.front(), 0};
cat.pop();
return res;
}

if (cat.front() > dog.front())
{
res = {dog.front(), 1};
dog.pop();
return res;
}
return res;
}

vector<int> dequeueDog() {
vector<int> res = {-1, -1};
if (dog.empty()) return res;
res = {dog.front(), 1};
dog.pop();
return res;
}

vector<int> dequeueCat() {
vector<int> res = {-1, -1};
if (cat.empty()) return res;
res = {cat.front(), 0};
cat.pop();
return res;
}
};

/**
* Your AnimalShelf object will be instantiated and called as such:
* AnimalShelf* obj = new AnimalShelf();
* obj->enqueue(animal);
* vector<int> param_2 = obj->dequeueAny();
* vector<int> param_3 = obj->dequeueDog();
* vector<int> param_4 = obj->dequeueCat();
*/

面试题 04.02. 最小高度树

问题地址:https://leetcode.cn/problems/minimum-height-tree-lcci/

给定一个有序整数数组,元素各不相同且按升序排列,编写一个算法,创建一棵高度最小的二叉搜索树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return helper(nums, 0, nums.size() - 1);
}
TreeNode* helper(vector<int>& nums, int left, int right) {
if (left > right) {
return nullptr;
}
int mid = (left + right) / 2;
auto root = new TreeNode(nums[mid]);
root->left = helper(nums, left, mid - 1);
root->right = helper(nums, mid + 1, right);
return root;
}
};

面试题 04.04. 检查平衡性

问题地址:https://leetcode.cn/problems/check-balance-lcci/

实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isBalanced(TreeNode* root) {
if (root == nullptr) {
return true;
} else {
return abs(height(root->left) - height(root->right)) <= 1 &&
isBalanced(root->left) &&
isBalanced(root->right);
}
}
int height(TreeNode* root) {
if (root == nullptr) {
return 0;
} else {
return max(height(root->left), height(root->right)) + 1;
}
}
};

面试题 05.01. 插入

问题地址:https://leetcode.cn/problems/insert-into-bits-lcci/

给定两个整型数字 N 与 M,以及表示比特位置的 i 与 j(i <= j,且从 0 位开始计算)。

编写一种方法,使 M 对应的二进制数字插入 N 对应的二进制数字的第 i ~ j 位区域,不足之处用 0 补齐。具体插入过程如图所示。

题目保证从 i 位到 j 位足以容纳 M, 例如: M = 10011,则 i~j 区域至少可容纳 5 位。

1
2
3
4
5
6
7
8
9
class Solution {
public:
int insertBits(int N, int M, int i, int j) {
for (int k = i; k <= j; ++k) {
N &= ~(1 << k);
}
return N + (M << i);
}
};

面试题 05.03. 翻转数位

问题地址:https://leetcode.cn/problems/reverse-bits-lcci/

给定一个32位整数 num,你可以将一个数位从0变为1。请编写一个程序,找出你能够获得的最长的一串1的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int reverseBits(int num) {
bitset<32> bst(num);
int cnt1 = 0, cnt2 = 0;
bool flag = false;
int ans = 1;
int i = 0;
while (i < 32) {
cnt2 = 0;
while (i < 32 && bst[i]) {
++i;
++cnt2;
}
ans = max(ans, flag ? (cnt1 + cnt2 + 1) : (cnt2 + 1));
cnt1 = cnt2;
cnt2 = 0;
while (i < 32 && !bst[i]) {
++i;
++cnt2;
}
flag = cnt2 == 1;
}
return min(ans, 32);
}
};

面试题 05.06. 整数转换

问题地址:https://leetcode.cn/problems/convert-integer-lcci/

整数转换。编写一个函数,确定需要改变几个位才能将整数A转成整数B。

1
2
3
4
5
6
7
8
9
10
class Solution {
public:
int convertInteger(int A, int B) {
int res = 0;
for (unsigned c = A ^ B; c != 0; c = c >> 1) {
res += c & 1;
}
return res;
}
};

面试题 08.01. 三步问题

问题地址:https://leetcode.cn/problems/three-steps-problem-lcci/

三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int waysToStep(int n) {
if (n <= 2) return n;
vector<int> dp(n + 1, 0);
dp[1] = 1, dp[2] = 2, dp[3] = 4;
for (auto i = 4; i < dp.size(); ++i) {
dp[i] = ((dp[i - 1] + dp[i - 2]) % 1000000007 + dp[i - 3]) % 1000000007;
}
return dp.back();
}
};

面试题 08.03. 魔术索引

问题地址:https://leetcode.cn/problems/magic-index-lcci/

魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int findMagicIndex(vector<int>& nums) {
return getAnswer(nums, 0, nums.size() - 1);
}
int getAnswer(vector<int>& nums, int left, int right) {
if (left > right) {
return -1;
}
int mid = left + (right - left) / 2;
int leftAnswer = getAnswer(nums, left, mid - 1);
if (leftAnswer != -1) {
return leftAnswer;
} else if (nums[mid] == mid) {
return mid;
}
return getAnswer(nums, mid + 1, right);
}
};

面试题 08.06. 汉诺塔问题

问题地址:https://leetcode.cn/problems/hanota-lcci/

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
int n = A.size();
move(n, A, B, C);
}
void move(int n, vector<int>& A, vector<int>& B, vector<int>& C) {
if (n == 1) {
C.push_back(A.back());
A.pop_back();
return;
}
move(n - 1, A, C, B);
C.push_back(A.back());
A.pop_back();
move(n - 1, B, A, C);
}
};

面试题 08.10. 颜色填充

问题地址:https://leetcode.cn/problems/color-fill-lcci/

编写函数,实现许多图片编辑软件都支持的「颜色填充」功能。

待填充的图像用二维数组 image 表示,元素为初始颜色值。初始坐标点的行坐标为 sr 列坐标为 sc。需要填充的新颜色为 newColor 。

「周围区域」是指颜色相同且在上、下、左、右四个方向上存在相连情况的若干元素。

请用新颜色填充初始坐标点的周围区域,并返回填充后的图像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
private:
const int dx[4] = {1, 0, 0, -1};
const int dy[4] = {0, 1, -1, 0};
public:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
int currColor = image[sr][sc];
if (currColor != newColor) {
dfs(image, sr, sc, currColor, newColor);
}
return image;
}
void dfs(vector<vector<int>>& image, int x, int y, int color, int newColor) {
if (image[x][y] == color) {
image[x][y] = newColor;
for (int i = 0; i < 4; i++) {
int mx = x + dx[i], my = y + dy[i];
if (mx >= 0 && mx < image.size() && my >= 0 && my < image[0].size()) {
dfs(image, mx, my, color, newColor);
}
}
}
}
};

面试题 10.01. 合并排序的数组

问题地址:https://leetcode.cn/problems/sorted-merge-lcci/

给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。

初始化 A 和 B 的元素数量分别为 m 和 n。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
void merge(vector<int>& A, int m, vector<int>& B, int n) {
int idx1 = m - 1;
int idx2 = n - 1;
int cur = m + n - 1;
while (idx1 > -1 && idx2 > -1) {
if (A[idx1] < B[idx2]) {
A[cur] = B[idx2];
idx2--;
} else {
A[cur] = A[idx1];
idx1--;
}
cur--;
}
if (idx2 != -1) {
for (int i = 0; i <= idx2; ++i) {
A[i] = B[i];
}
}
}
};

面试题 10.05. 稀疏数组搜索

问题地址:https://leetcode.cn/problems/sparse-array-search-lcci/

稀疏数组搜索。有个排好序的字符串数组,其中散布着一些空字符串,编写一种方法,找出给定字符串的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
int findString(vector<string>& words, string s) {
int left = 0, right = words.size() - 1;
while (left <= right) {
if (words[left].size() == 0) {
left++;
continue;
}
if (words[right].size() == 0) {
right--;
continue;
}
int mid = (left + right) / 2;
while (words[mid].size() == 0) {
mid++;
if (mid == right) {
right = (left + right) / 2;
continue;
}
}
if (words[mid] == s) {
return mid;
} else if (words[mid] > s) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
};

面试题 16.05. 阶乘尾数

问题地址:https://leetcode.cn/problems/factorial-zeros-lcci/

设计一个算法,算出 n 阶乘有多少个尾随零。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int trailingZeroes(int n) {
int ans = 0;
while (n) {
n /= 5;
ans += n;
}
return ans;
}
};

面试题 16.07. 最大数值

问题地址:https://leetcode.cn/problems/maximum-lcci/

编写一个方法,找出两个数字a和b中最大的那一个。不得使用if-else或其他比较运算符。

1
2
3
4
5
6
7
class Solution {
public:
int maximum(int a, int b) {
bool sign = ((long)a - (long)b) >> 63;
return a * (int)(!sign) + b * (int)sign;
}
};

面试题 16.11. 跳水板

问题地址:https://leetcode.cn/problems/diving-board-lcci/

你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。

返回的长度需要从小到大排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
vector<int> divingBoard(int shorter, int longer, int k) {
if (k == 0) {
return vector<int>();
}
if (shorter == longer) {
return vector<int>(1, shorter * k);
}
vector<int> lengths(k + 1);
for (int i = 0; i <= k; ++i) {
lengths[i] = shorter * (k - i) + longer * i;
}
return lengths;
}
};

面试题 16.17. 连续数列

问题地址:https://leetcode.cn/problems/contiguous-sequence-lcci/

给定一个整数数组,找出总和最大的连续数列,并返回总和。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0, maxAns = nums[0];
for (const auto &x : nums) {
pre = max(pre + x, x);
maxAns = max(maxAns, pre);
}
return maxAns;
}
};

543. 二叉树的直径

问题地址:https://leetcode.cn/problems/diameter-of-binary-tree/

给你一棵二叉树的根节点,返回该树的 直径 。

二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。

两节点之间路径的 长度 由它们之间边数表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
int ans;
int depth(TreeNode* root) {
if (root == nullptr) {
return 0;
}
int l = depth(root->left);
int r = depth(root->right);
ans = max(ans, l + r + 1);
return max(l, r) + 1;
}
public:
int diameterOfBinaryTree(TreeNode* root) {
ans = 1;
depth(root);
return ans - 1;
}
};

349. 两个数组的交集

问题地址:https://leetcode.cn/problems/intersection-of-two-arrays/

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set;
unordered_set<int> set(nums1.begin(), nums1.end());
for (auto num : nums2) {
if (set.find(num) != set.end()) {
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};

350. 两个数组的交集 II

问题地址:https://leetcode.cn/problems/intersection-of-two-arrays-ii/

给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
int len1 = nums1.size(), len2 = nums2.size();
vector<int> intersection;
int index1 = 0, index2 = 0;
while (index1 < len1 && index2 < len2) {
if (nums1[index1] < nums2[index2]) {
index1++;
} else if (nums1[index1] > nums2[index2]) {
index2++;
} else {
intersection.push_back(nums1[index1]);
index1++;
index2++;
}
}
return intersection;
}
};

367. 有效的完全平方数

问题地址:https://leetcode.cn/problems/valid-perfect-square/

给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。

不能使用任何内置的库函数,如  sqrt 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
bool isPerfectSquare(int num) {
int left = 0, right = num;
while (left <= right) {
int mid = left + (right - left) / 2;
long square = (long) mid * mid;
if (square < num) {
left = mid + 1;
} else if (square > num) {
right = mid - 1;
} else {
return true;
}
}
return false;
}
};

387. 字符串中的第一个唯一字符

问题地址:https://leetcode.cn/problems/first-unique-character-in-a-string/

给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int firstUniqChar(string s) {
unordered_map<char, int> frequency;
for (auto ch : s) {
++frequency[ch];
}
for (auto i = 0; i < s.size(); ++i) {
if (frequency[s[i]] == 1) {
return i;
}
}
return -1;
}
};

389. 找不同

问题地址:https://leetcode.cn/problems/find-the-difference/

给定两个字符串 s 和 t ,它们只包含小写字母。

字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。

请找出在 t 中被添加的字母。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
char findTheDifference(string s, string t) {
vector<int> cnt(26, 0);
for (auto ch : s) {
cnt[ch - 'a']++;
}
for (auto ch : t) {
cnt[ch - 'a']--;
if (cnt[ch - 'a'] < 0) {
return ch;
}
}
return ' ';
}
};

409. 最长回文串

问题地址:https://leetcode.cn/problems/longest-palindrome/

给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的回文串 。

在构造过程中,请注意 区分大小写 。比如 “Aa” 不能当做一个回文字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int longestPalindrome(string s) {
unordered_map<char, int> count;
int ans = 0;
for (char c : s) {
++count[c];
}
for (auto p : count) {
int v = p.second;
ans += v / 2 * 2;
if (v % 2 == 1 and ans % 2 == 0) {
++ans;
}
}
return ans;
}
};

414. 第三大的数

问题地址:https://leetcode.cn/problems/third-maximum-number/

给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int thirdMax(vector<int>& nums) {
sort(nums.begin(), nums.end(), greater<>());
for (auto i = 1, diff = 1; i < nums.size(); ++i) {
if (nums[i] != nums[i - 1] && ++diff == 3) {
return nums[i];
}
}
return nums[0];
}
};

415. 字符串相加

问题地址:https://leetcode.cn/problems/add-strings/

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
string addStrings(string num1, string num2) {
int i = num1.length() - 1, j = num2.length() - 1, add = 0;
string ans = "";
while (i >= 0 || j >= 0 || add != 0) {
int x = i >= 0 ? num1[i] - '0' : 0;
int y = j >= 0 ? num2[j] - '0' : 0;
int result = x + y + add;
ans.push_back('0' + result % 10);
add = result / 10;
i -= 1;
j -= 1;
}
reverse(ans.begin(), ans.end());
return ans;
}
};

434. 字符串中的单词数

问题地址:https://leetcode.cn/problems/number-of-segments-in-a-string/

统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。

请注意,你可以假定字符串里不包括任何不可打印的字符。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int countSegments(string s) {
int count = 0;
for (auto i = 0; i < s.size(); i++) {
if ((i == 0 || s[i - 1] == ' ') && s[i] != ' ') {
count++;
}
}
return count;
}
};

559. N 叉树的最大深度

问题地址:https://leetcode.cn/problems/maximum-depth-of-n-ary-tree/

给定一个 N 叉树,找到其最大深度。

最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。

N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;

Node() {}

Node(int _val) {
val = _val;
}

Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/

class Solution {
public:
int maxDepth(Node* root) {
if (root == nullptr) {
return 0;
}
int maxChildDepth = 0;
vector<Node *> children = root->children;
for (auto child : children) {
int childDepth = maxDepth(child);
maxChildDepth = max(maxChildDepth, childDepth);
}
return maxChildDepth + 1;
}
};

561. 数组拆分

问题地址:https://leetcode.cn/problems/array-partition/

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。

返回该 最大总和 。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int arrayPairSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
int ans = 0;
for (auto i = 0; i < nums.size(); i += 2) {
ans += nums[i];
}
return ans;
}
};

590. N 叉树的后序遍历

问题地址:https://leetcode.cn/problems/n-ary-tree-postorder-traversal/

给定一个 n 叉树的根节点 root ,返回 其节点值的 后序遍历 。

n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;

Node() {}

Node(int _val) {
val = _val;
}

Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/

class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> res;
helper(root, res);
return res;
}
void helper(const Node* root, vector<int>& res) {
if (root == nullptr) {
return;
}
for (auto & ch : root->children) {
helper(ch, res);
}
res.emplace_back(root->val);
}
};

671. 二叉树中第二小的节点

问题地址:https://leetcode.cn/problems/second-minimum-node-in-a-binary-tree/

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。

更正式地说,即 root.val = min(root.left.val, root.right.val) 总成立。

给出这样的一个二叉树,你需要输出所有节点中的 第二小的值 。

如果第二小的值不存在的话,输出 -1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int findSecondMinimumValue(TreeNode* root) {
set<int> s;
inorder(root, s);
if (s.size() < 2) {
return -1;
} else {
auto it = ++s.begin();
return *it;
}
}
void inorder(TreeNode* root, set<int>& s) {
if (!root) return;
inorder(root->left, s);
s.insert(root->val);
inorder(root->right, s);
}
};

中等

LCR 095. 最长公共子序列

问题地址:https://leetcode.cn/problems/qJnOS7/

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,"ace""abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m = text1.length(), n = text2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 1; i <= m; i++) {
char c1 = text1.at(i - 1);
for (int j = 1; j <= n; j++) {
char c2 = text2.at(j - 1);
if (c1 == c2) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
};

1717. 删除子字符串的最大得分

问题地址:https://leetcode.cn/problems/maximum-score-from-removing-substrings/

给你一个字符串 s 和两个整数 x 和 y 。你可以执行下面两种操作任意次。

  • 删除子字符串 "ab" 并得到 x 分。
    • 比方说,从 "cabxbae" 删除 ab ,得到 "cxbae" 。
  • 删除子字符串 "ba" 并得到 y 分。
    • 比方说,从 "cabxbae" 删除 ba ,得到 "cabxe" 。

请返回对 s 字符串执行上面操作若干次能得到的最大得分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
public:
int maximumGain(string s, int x, int y) {
int n = s.length();
if (x < y) {
swap(x, y);
for (int i = 0; i < n; i++) {
if (s[i] == 'a') s[i] = 'b';
else if (s[i] == 'b') s[i] = 'a';
}
}

int ret = 0;
int i = 0;
while (i < n) {
while (i < n && s[i] != 'a' && s[i] != 'b') i++;

int ca = 0, cb = 0;
while (i < n && (s[i] == 'a' || s[i] == 'b')) {
if (s[i] == 'a') {
ca++;
} else {
if (ca > 0) {
ca--;
ret += x;
} else {
cb++;
}
}
i++;
}

ret += min(ca, cb) * y;
}

return ret;
}
};

2256. 最小平均差

问题地址:https://leetcode.cn/problems/minimum-average-difference/

给你一个下标从 0 开始长度为 n 的整数数组 nums 。

下标 i 处的 平均差 指的是 nums 中 前 i + 1 个元素平均值和 后 n - i - 1 个元素平均值的 绝对差 。两个平均值都需要 向下取整 到最近的整数。

请你返回产生 最小平均差 的下标。如果有多个下标最小平均差相等,请你返回 最小 的一个下标。

注意:

  • 两个数的 绝对差 是两者差的绝对值。
  • n 个元素的平均值是 n 个元素之  除以(整数除法) n 。
  • 0 个元素的平均值视为 0 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int minimumAverageDifference(vector<int>& nums) {
long sum = 0;
for (auto &num : nums) {
sum += num;
}
long preSum = 0;
int mi = INT_MAX;
int n = nums.size();
int ans = 0;
for (int i = 0; i < n; i++) {
preSum += nums[i];
long last = (i == n - 1) ? 0 : (sum - preSum) / (n - i - 1);
long diff = abs(preSum / (i + 1) - last); /* 前后数组和的差值 */
if (mi > diff) {
ans = i;
mi = diff;
}
}
return ans;
}
};

1513. 仅含 1 的子串数

问题地址:https://leetcode.cn/problems/number-of-substrings-with-only-1s/

给你一个二进制字符串 s(仅由 '0''1' 组成的字符串)。

返回所有字符都为 1 的子字符串的数目。

由于答案可能很大,请你将它对 10^9 + 7 取模后返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
static constexpr int P = int(1E9) + 7;

int numSub(string s) {
int p = 0;
long long ans = 0;
while (p < s.size()) {
if (s[p] == '0') {
++p;
continue;
}
int cnt = 0;
while (p < s.size() && s[p] == '1') {
++cnt;
++p;
}
ans = ans + (1LL + (long long)cnt) * cnt / 2;
ans = ans % P;
}
return ans;
}
};

1898. 可移除字符的最大数目

问题地址:https://leetcode.cn/problems/maximum-number-of-removable-characters/

给你两个字符串 sp ,其中 ps 的一个 子序列 。同时,给你一个元素 互不相同 且下标 从 0 开始 计数的整数数组 removable ,该数组是 s 中下标的一个子集(s 的下标也 从 0 开始 计数)。

请你找出一个整数 k(0 <= k <= removable.length),选出 removable 中的 前 k 个下标,然后从 s 中移除这些下标对应的 k 个字符。整数 k 需满足:在执行完上述步骤后, p 仍然是 s 的一个 子序列 。更正式的解释是,对于每个 0 <= i < k ,先标记出位于 s[removable[i]] 的字符,接着移除所有标记过的字符,然后检查 p 是否仍然是 s 的一个子序列。

返回你可以找出的 最大 k ,满足在移除字符后 p 仍然是 s 的一个子序列。

字符串的一个 子序列 是一个由原字符串生成的新字符串,生成过程中可能会移除原字符串中的一些字符(也可能不移除)但不改变剩余字符之间的相对顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
public:
int maximumRemovals(string s, string p, vector<int>& removable) {
int ns = s.size();
int np = p.size();
int n = removable.size();
// 辅助函数,用来判断移除 k 个下标后 p 是否是 s_k 的子序列
auto check = [&](int k) -> bool {
vector<int> state(ns, 1); // s 中每个字符的状态
for (int i = 0; i < k; ++i){
state[removable[i]] = 0;
}
// 匹配 s_k 与 p
int j = 0;
for (int i = 0; i < ns; ++i){
// s[i] 未被删除且与 p[j] 相等时,匹配成功,增加 j
if (state[i] && s[i] == p[j]){
++j;
if (j == np){
return true;
}
}
}
return false;
};

// 二分查找
int l = 0;
int r = n + 1;
while (l < r){
int mid = l + (r - l) / 2;
if (check(mid)){
l = mid + 1;
}
else{
r = mid;
}
}
return l - 1;

}
};

1300. 转变数组后最接近目标值的数组和

问题地址:https://leetcode.cn/problems/sum-of-mutated-array-closest-to-target/

给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近  target (最接近表示两者之差的绝对值最小)。

如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

请注意,答案不一定是 arr 中的数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int findBestValue(vector<int>& arr, int target) {
sort(arr.begin(), arr.end());
int n = arr.size();
vector<int> prefix(n + 1);
for (int i = 1; i <= n; ++i) {
prefix[i] = prefix[i - 1] + arr[i - 1];
}

int r = *max_element(arr.begin(), arr.end());
int ans = 0, diff = target;
for (int i = 1; i <= r; ++i) {
auto iter = lower_bound(arr.begin(), arr.end(), i);
int cur = prefix[iter - arr.begin()] + (arr.end() - iter) * i;
if (abs(cur - target) < diff) {
ans = i;
diff = abs(cur - target);
}
}
return ans;
}
};

78. 子集

问题地址:https://leetcode.cn/problems/subsets/

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<int> t;
vector<vector<int>> ans;

vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
for (int mask = 0; mask < (1 << n); ++mask) {
t.clear();
for (int i = 0; i < n; ++i) {
if (mask & (1 << i)) {
t.push_back(nums[i]);
}
}
ans.push_back(t);
}
return ans;
}
};

2597. 美丽子集的数目

问题地址:https://leetcode.cn/problems/the-number-of-beautiful-subsets/

给你一个由正整数组成的数组 nums 和一个 整数 k

如果 nums 的子集中,任意两个整数的绝对差均不等于 k ,则认为该子数组是一个 美丽 子集。

返回数组 nums非空美丽 的子集数目。

nums 的子集定义为:可以经由 nums 删除某些元素(也可能不删除)得到的一个数组。只有在删除元素时选择的索引不同的情况下,两个子集才会被视作是不同的子集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int beautifulSubsets(vector<int> &nums, int k) {
int ans = -1; // 去掉空集
int cnt[3001]{}; // 用数组实现比哈希表更快
function<void(int)> dfs = [&](int i) {
if (i == nums.size()) {
ans++;
return;
}
dfs(i + 1); // 不选
int x = nums[i] + k; // 避免负数下标
if (cnt[x - k] == 0 && cnt[x + k] == 0) {
++cnt[x]; // 选
dfs(i + 1);
--cnt[x]; // 恢复现场
}
};
dfs(0);
return ans;
}
};

1457. 二叉树中的伪回文路径

问题地址:https://leetcode.cn/problems/pseudo-palindromic-paths-in-a-binary-tree/

给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。

请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int check(int *cnt) {
int odd = 0;
for (int i = 0; i <= 9; i++) {
if (cnt[i] & 1) {
odd++;
}
}
if (odd <= 1) {
return 1;
}
return 0;
}

int dfs(TreeNode *root, int *cnt) {
if (root == nullptr) {
return 0;
}
cnt[root->val]++;
if (root->left == nullptr && root->right == nullptr) {
int anw = check(cnt);
cnt[root->val]--;
return anw;
}
int anw = 0;
if (root->left != nullptr) {
anw += dfs(root->left, cnt);
}
if (root->right != nullptr) {
anw += dfs(root->right, cnt);
}
cnt[root->val]--;
return anw;
}

int pseudoPalindromicPaths (TreeNode* root) {
int cnt[10] = {0};
return dfs(root, cnt);
}
};

720. 词典中最长的单词

问题地址:https://leetcode.cn/problems/longest-word-in-dictionary/

给出一个字符串数组 words 组成的一本英语词典。返回 words 中最长的一个单词,该单词是由 words 词典中其他单词逐步添加一个字母组成。

若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
string longestWord(vector<string>& words) {
sort(words.begin(), words.end(), [](const string &a, const string &b) {
return a.size() != b.size() ? a.size() < b.size() : a > b;
});
string longest;
unordered_set<string> candidates = {""};
for (const auto &word : words) {
if (candidates.count(word.substr(0, word.size() - 1))) {
candidates.emplace(word);
longest = word;
}
}
return longest;
}
};

198. 打家劫舍

问题地址:https://leetcode.cn/problems/house-robber/

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 0) {
return 0;
}

int N = nums.size();
vector<int> dp(N+1, 0);
dp[0] = 0;
dp[1] = nums[0];
for (int k = 2; k <= N; k++) {
dp[k] = max(dp[k-1], nums[k-1] + dp[k-2]);
}
return dp[N];
}
};

50. Pow(x, n)

问题地址:https://leetcode.cn/problems/powx-n/

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xnx^n )。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
double quickMul(double x, long long N) {
double ans = 1.0;
double x_contribute = x;
while (N > 0) {
if (N % 2 == 1) {
ans *= x_contribute;
}
x_contribute *= x_contribute;
N /= 2;
}
return ans;
}
double myPow(double x, int n) {
long long N = n;
return N >= 0 ? quickMul(x, N) : 1.0 /quickMul(x, -N);
}
};

1922. 统计好数字的数目

问题地址:https://leetcode.cn/problems/count-good-numbers/

我们称一个数字字符串是 好数字 当它满足(下标从 0 开始)偶数 下标处的数字为 偶数 且 奇数 下标处的数字为 质数 (2,3,5 或 7)。

  • 比方说,"2582" 是好数字,因为偶数下标处的数字(2 和 8)是偶数且奇数下标处的数字(5 和 2)为质数。但 "3245" 不是 好数字,因为 3 在偶数下标处但不是偶数。

给你一个整数 n ,请你返回长度为 n 且为好数字的数字字符串 总数 。由于答案可能会很大,请你将它对 109+710^9 + 7 取余后返回 。

一个 数字字符串 是每一位都由 0 到 9 组成的字符串,且可能包含前导 0 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
private:
static constexpr int mod = 1e9 + 7;

public:
int countGoodNumbers(long long n) {
auto quickmul = [](int x, long long y) -> int {
int ret = 1, mul = x;
while (y > 0) {
if (y % 2 == 1) {
ret = (long long)ret * mul % mod;
}
mul = (long long)mul * mul % mod;
y /= 2;
}
return ret;
};

return (long long)quickmul(5, (n + 1) / 2) * quickmul(4, n / 2) % mod;
}
};

86. 分隔链表

问题地址:https://leetcode.cn/problems/partition-list/

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* small = new ListNode(0);
ListNode* smallHead = small;
ListNode* large = new ListNode(0);
ListNode* largeHead = large;
while (head != nullptr) {
if (head->val < x) {
small->next = head;
small = small->next;
} else {
large->next = head;
large = large->next;
}
head = head->next;
}
large->next = nullptr;
small->next = largeHead->next;
return smallHead->next;
}
};

2531. 使字符串总不同字符的数目相等

问题地址:https://leetcode.cn/problems/make-number-of-distinct-characters-equal/

给你两个下标从 0 开始的字符串 word1word2

一次 移动 由以下两个步骤组成:

  • 选中两个下标 ij ,分别满足 0 <= i < word1.length0 <= j < word2.length
  • 交换 word1[i]word2[j]

如果可以通过 恰好一次 移动,使 word1word2 中不同字符的数目相等,则返回 true ;否则,返回 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
bool isItPossible(string word1, string word2) {
unordered_map<char, int> c1, c2;
for (char c : word1) ++c1[c];
for (char c : word2) ++c2[c];
for (auto[x, c] : c1) {
for (auto[y, d] : c2) {
if (y == x) {
if (c1.size() == c2.size()) return true;
} else if (c1.size() - (c == 1) + !c1.count(y) ==
c2.size() - (d == 1) + !c2.count(x))
return true;
}
}
return false;
}
};

494. 目标和

问题地址:https://leetcode.cn/problems/target-sum/

给你一个非负整数数组 nums 和一个整数 target

向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int count = 0;

int findTargetSumWays(vector<int>& nums, int target) {
backtrack(nums, target, 0, 0);
return count;
}

void backtrack(vector<int>& nums, int target, int index, int sum) {
if (index == nums.size()) {
if (sum == target) {
count++;
}
} else {
backtrack(nums, target, index + 1, sum + nums[index]);
backtrack(nums, target, index + 1, sum - nums[index]);
}
}
};

535. TinyURL 的加密与解密

问题地址:https://leetcode.cn/problems/encode-and-decode-tinyurl/

TinyURL 是一种 URL 简化服务, 比如:当你输入一个 URL https://leetcode.com/problems/design-tinyurl 时,它将返回一个简化的URL http://tinyurl.com/4e9iAk 。请你设计一个类来加密与解密 TinyURL 。

加密和解密算法如何设计和运作是没有限制的,你只需要保证一个 URL 可以被加密成一个 TinyURL ,并且这个 TinyURL 可以用解密方法恢复成原本的 URL 。

实现 Solution 类:

  • Solution() 初始化 TinyURL 系统对象。
  • String encode(String longUrl) 返回 longUrl 对应的 TinyURL 。
  • String decode(String shortUrl) 返回 shortUrl 原本的 URL 。题目数据保证给定的 shortUrl 是由同一个系统对象加密的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
private:
unordered_map<int, string> dataBase;
int id;
public:
Solution() {
id = 0;
}

// Encodes a URL to a shortened URL.
string encode(string longUrl) {
id++;
dataBase[id] = longUrl;
return string("http://tinyurl.com/") + to_string(id);
}

// Decodes a shortened URL to its original URL.
string decode(string shortUrl) {
int p = shortUrl.rfind('/') + 1;
int key = stoi(shortUrl.substr(p, int(shortUrl.size()) - p));
return dataBase[key];
}
};

215. 数组中的第K个最大元素

问题地址:https://leetcode.cn/problems/kth-largest-element-in-an-array/

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public:
int quickSelect(vector<int>& a, int l, int r, int index) {
int q = randomPartition(a, l, r);
if (q == index) {
return a[q];
} else {
return q < index ? quickSelect(a, q + 1, r, index) : quickSelect(a, l, q - 1, index);
}
}

inline int randomPartition(vector<int>& a, int l, int r) {
int i = rand() % (r - l + 1) + l;
swap(a[i], a[r]);
return partition(a, l, r);
}

inline int partition(vector<int>& a, int l, int r) {
int x = a[r], i = l - 1;
for (int j = l; j < r; ++j) {
if (a[j] <= x) {
swap(a[++i], a[j]);
}
}
swap(a[i + 1], a[r]);
return i + 1;
}

int findKthLargest(vector<int>& nums, int k) {
srand(time(0));
return quickSelect(nums, 0, nums.size() - 1, nums.size() - k);
}
};

2304. 网格中的最小路径代价

问题地址:https://leetcode.cn/problems/minimum-path-cost-in-a-grid/

给你一个下标从 0 开始的整数矩阵 grid ,矩阵大小为 m x n ,由从 0m * n - 1 的不同整数组成。你可以在此矩阵中,从一个单元格移动到 下一行 的任何其他单元格。如果你位于单元格 (x, y) ,且满足 x < m - 1 ,你可以移动到 (x + 1, 0), (x + 1, 1), …, (x + 1, n - 1) 中的任何一个单元格。注意: 在最后一行中的单元格不能触发移动。

每次可能的移动都需要付出对应的代价,代价用一个下标从 0 开始的二维数组 moveCost 表示,该数组大小为 (m * n) x n ,其中 moveCost[i][j] 是从值为 i 的单元格移动到下一行第 j 列单元格的代价。从 grid 最后一行的单元格移动的代价可以忽略。

grid 一条路径的代价是:所有路径经过的单元格的 值之和 加上 所有移动的 代价之和 。从 第一行 任意单元格出发,返回到达 最后一行 任意单元格的最小路径代价。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int minPathCost(vector<vector<int>>& grid, vector<vector<int>>& moveCost) {
int m = grid.size(), n = grid[0].size();

vector<vector<int>> f;
f.resize(m, vector<int>(n));
for (int j = 0; j < n; j++) f[0][j] = grid[0][j];
for (int i = 1; i < m; i++) for (int j = 0; j < n; j++) {
f[i][j] = 1e9;
for (int k = 0; k < n; k++) f[i][j] = min(f[i][j], f[i - 1][k] + moveCost[grid[i - 1][k]][j] + grid[i][j]);
}

int ans = 1e9;
for (int j = 0; j < n; j++) ans = min(ans, f[m - 1][j]);
return ans;
}
};

139. 单词拆分

问题地址:https://leetcode.cn/problems/word-break/

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
auto wordDictSet = unordered_set<string>();
for (auto word : wordDict) {
wordDictSet.insert(word);
}

auto dp = vector<bool>(s.size() + 1);
dp[0] = true;
for (int i = 1; i <= s.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (dp[j] && wordDictSet.find(s.substr(j, i - j)) != wordDictSet.end()) {
dp[i] = true;
break;
}
}
}
return dp[s.size()];
}
};

731. 我的日程安排表 II

问题地址:https://leetcode.cn/problems/my-calendar-ii/

实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排。

MyCalendar 有一个 book(int start, int end)方法。它意味着在 startend 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为,  start <= x < end

当三个日程安排有一些时间上的交叉时(例如三个日程安排都在同一时间内),就会产生三重预订。

每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致三重预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。

请按照以下步骤调用MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyCalendarTwo {
public:
MyCalendarTwo() {

}

bool book(int start, int end) {
for (auto &[l, r] : overlaps) {
if (l < end && start < r) {
return false;
}
}
for (auto &[l, r] : booked) {
if (l < end && start < r) {
overlaps.emplace_back(max(l, start), min(r, end));
}
}
booked.emplace_back(start, end);
return true;
}
private:
vector<pair<int, int>> booked;
vector<pair<int, int>> overlaps;
};

LCR 007. 三数之和

问题地址:https://leetcode.cn/problems/1fGaJU/

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 abc ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
ans.push_back({nums[first], nums[second], nums[third]});
}
}
}
return ans;
}
};

1594. 矩阵的最大非负积

问题地址:https://leetcode.cn/problems/maximum-non-negative-product-in-a-matrix/

给你一个大小为 m x n 的矩阵 grid 。最初,你位于左上角 (0, 0) ,每一步,你可以在矩阵中 向右向下 移动。

在从左上角 (0, 0) 开始到右下角 (m - 1, n - 1) 结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。

返回 最大非负积 对 109 + 7 取余 的结果。如果最大积为 负数 ,则返回 -1

注意,取余是在得到最大积之后执行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
int maxProductPath(vector<vector<int>>& grid) {
const int mod = 1000000000 + 7;
int m = grid.size(), n = grid[0].size();
vector<vector<long long>> maxgt(m, vector<long long>(n));
vector<vector<long long>> minlt(m, vector<long long>(n));

maxgt[0][0] = minlt[0][0] = grid[0][0];
for (int i = 1; i < n; i++) {
maxgt[0][i] = minlt[0][i] = maxgt[0][i - 1] * grid[0][i];
}
for (int i = 1; i < m; i++) {
maxgt[i][0] = minlt[i][0] = maxgt[i - 1][0] * grid[i][0];
}

for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (grid[i][j] >= 0) {
maxgt[i][j] = max(maxgt[i][j - 1], maxgt[i - 1][j]) * grid[i][j];
minlt[i][j] = min(minlt[i][j - 1], minlt[i - 1][j]) * grid[i][j];
} else {
maxgt[i][j] = min(minlt[i][j - 1], minlt[i - 1][j]) * grid[i][j];
minlt[i][j] = max(maxgt[i][j - 1], maxgt[i - 1][j]) * grid[i][j];
}
}
}
if (maxgt[m - 1][n - 1] < 0) {
return -1;
} else {
return maxgt[m - 1][n - 1] % mod;
}
}
};

面试题 16.16. 部分排序

问题地址:https://leetcode.cn/problems/sub-sort-lcci/

给定一个整数数组,编写一个函数,找出索引mn,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的mn(例如整个数组是有序的),请返回[-1,-1]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
vector<int> subSort(vector<int>& array) {
int n = array.size();
int maxx = INT_MIN, minn = INT_MAX;
int l = -1, r = -1;
for (int i = 0; i < n; ++i) {
if (array[i] < maxx) r = i;
else maxx = array[i];
}
for (int i = n - 1; i >= 0; --i) {
if (array[i] > minn) l = i;
else minn = array[i];
}
return {l, r};
}
};

328. 奇偶链表

问题地址:https://leetcode.cn/problems/odd-even-linked-list/

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if (head == nullptr) {
return head;
}
ListNode * evenHead = head->next;
ListNode * odd = head;
ListNode * even = evenHead;
while (even != nullptr && even->next != nullptr) {
odd->next = even->next;
odd = odd->next;
even->next = odd->next;
even = even->next;
}
odd->next = evenHead;
return head;
}
};

994. 腐烂的橘子

问题地址:https://leetcode.cn/problems/rotting-oranges/

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

  • 值 0 代表空单元格;
  • 值 1 代表新鲜橘子;
  • 值 2 代表腐烂的橘子。

每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution {
private:
int cnt;
int dis[10][10];
int dir_x[4] = {0, 1, 0, -1};
int dir_y[4] = {1, 0, -1, 0};
public:
int orangesRotting(vector<vector<int>>& grid) {
queue<pair<int, int>> Q;
memset(dis, -1, sizeof(dis));
cnt = 0;
int m = (int)grid.size(), n = (int)grid[0].size(), ans = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == 2) {
Q.push(make_pair(i, j));
dis[i][j] = 0;
}
else if (grid[i][j] == 1) cnt += 1;
}
}
while (!Q.empty()) {
pair<int, int> x = Q.front();
Q.pop();
for (int i = 0; i < 4; i++) {
int tx = x.first + dir_x[i];
int ty = x.second + dir_y[i];
if (tx < 0 || tx >= m || ty < 0 || ty >= n || ~dis[tx][ty] || !grid[tx][ty]) continue;
dis[tx][ty] = dis[x.first][x.second] + 1;
Q.push(make_pair(tx, ty));
if (grid[tx][ty] == 1) {
cnt -= 1;
ans = dis[tx][ty];
}
}
if (!cnt) break;
}
return cnt ? -1 : ans;
}
};

919. 完全二叉树插入器

问题地址:https://leetcode.cn/problems/complete-binary-tree-inserter/

完全二叉树 是每一层(除最后一层外)都是完全填充(即,节点数达到最大)的,并且所有的节点都尽可能地集中在左侧。

设计一种算法,将一个新节点插入到一个完整的二叉树中,并在插入后保持其完整。

实现 CBTInserter 类:

  • CBTInserter(TreeNode root) 使用头节点为 root 的给定树初始化该数据结构;
  • CBTInserter.insert(int v)  向树中插入一个值为 Node.val == val 的新节点 TreeNode。使树保持完全二叉树的状态,并返回插入节点 TreeNode 的父节点的值
  • CBTInserter.get_root() 将返回树的头节点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class CBTInserter {
public:
CBTInserter(TreeNode* root) {
this->root = root;

queue<TreeNode *> q;
q.push(root);

while (!q.empty()) {
TreeNode * node = q.front();
q.pop();
if (node->left) {
q.push(node->left);
}
if (node->right) {
q.push(node->right);
}
if (!(node->left && node->right)) {
candidate.push(node);
}
}
}

int insert(int val) {
TreeNode * child = new TreeNode(val);
TreeNode * node = candidate.front();
int ret = node->val;
if (!node->left) {
node->left = child;
} else {
node->right = child;
candidate.pop();
}
candidate.push(child);
return ret;
}

TreeNode* get_root() {
return root;
}

private:
queue<TreeNode *> candidate;
TreeNode * root;
};

/**
* Your CBTInserter object will be instantiated and called as such:
* CBTInserter* obj = new CBTInserter(root);
* int param_1 = obj->insert(val);
* TreeNode* param_2 = obj->get_root();
*/

2550. 猴子碰撞的方法数

问题地址:https://leetcode.cn/problems/count-collisions-of-monkeys-on-a-polygon/

现在有一个正凸多边形,其上共有 n 个顶点。顶点按顺时针方向从 0 到 n - 1 依次编号。每个顶点上 正好有一只猴子 。下图中是一个 6 个顶点的凸多边形。

每个猴子同时移动到相邻的顶点。顶点 i 的相邻顶点可以是:

  • 顺时针方向的顶点 (i + 1) % n ,或
  • 逆时针方向的顶点 (i - 1 + n) % n 。

如果移动后至少有两只猴子停留在同一个顶点上或者相交在一条边上,则会发生 碰撞

返回猴子至少发生 一次碰撞 的移动方法数。由于答案可能非常大,请返回对 109+710^9+7 取余后的结果。

注意,每只猴子只能移动一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using INT = long long;

class Solution {
public:
INT pow(INT x, INT N) {
INT ans = 1;
while (N) {
if (N & 1) {
ans = ((ans % mod) * (x % mod)) % mod;
}
x = (x % mod) * (x % mod);
N >>= 1;
}
return ans % mod;
}
int monkeyMove(int n) {
return (pow(2, n) - 2 + mod) % mod;
}

private:
const INT mod = 1e9 + 7;
};

LCP 41. 黑白翻转棋

问题地址:https://leetcode.cn/problems/fHi6rV/

在 n*m 大小的棋盘中,有黑白两种棋子,黑棋记作字母 “X”, 白棋记作字母 “O”,空余位置记作 “.”。当落下的棋子与其他相同颜色的棋子在行、列或对角线完全包围(中间不存在空白位置)另一种颜色的棋子,则可以翻转这些棋子的颜色。

「力扣挑战赛」黑白翻转棋项目中,将提供给选手一个未形成可翻转棋子的棋盘残局,其状态记作 chessboard。若下一步可放置一枚黑棋,请问选手最多能翻转多少枚白棋。

注意:

  • 若翻转白棋成黑棋后,棋盘上仍存在可以翻转的白棋,将可以 继续 翻转白棋
  • 输入数据保证初始棋盘状态无可以翻转的棋子且存在空余位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class Solution {
public:
const int dirs[8][2] = {
{1, 0}, {-1, 0}, {0, 1}, {0, -1},
{1, 1}, {1, -1}, {-1, 1}, {-1, -1}
};

bool judge(const vector<string>& chessboard, int x, int y, int dx, int dy) {
x += dx;
y += dy;
while (0 <= x && x < chessboard.size() && 0 <= y && y < chessboard[0].size()) {
if (chessboard[x][y] == 'X') {
return true;
} else if (chessboard[x][y] == '.') {
return false;
}
x += dx;
y += dy;
}
return false;
}

int bfs(vector<string> chessboard, int px, int py) {
int cnt = 0;
queue<pair<int, int>> q;
q.emplace(px, py);
chessboard[px][py] = 'X';
while (!q.empty()) {
pair<int, int> t = q.front();
q.pop();
for (int i = 0; i < 8; ++i) {
if (judge(chessboard, t.first, t.second, dirs[i][0], dirs[i][1])) {
int x = t.first + dirs[i][0], y = t.second + dirs[i][1];
while (chessboard[x][y] != 'X') {
q.emplace(x, y);
chessboard[x][y] = 'X';
x += dirs[i][0];
y += dirs[i][1];
++cnt;
}
}
}
}
return cnt;
}

int flipChess(vector<string>& chessboard) {
int res = 0;
for (int i = 0; i < chessboard.size(); ++i) {
for (int j = 0; j < chessboard[0].size(); ++j) {
if (chessboard[i][j] == '.') {
res = max(res, bfs(chessboard, i, j));
}
}
}
return res;
}
};

1249. 移除无效的括号

问题地址:https://leetcode.cn/problems/minimum-remove-to-make-valid-parentheses/

给你一个由 '('')' 和小写字母组成的字符串 s。

你需要从字符串中删除最少数目的 '(' 或者 ')' (可以删除任意位置的括号),使得剩下的「括号字符串」有效。

请返回任意一个合法字符串。

有效「括号字符串」应当符合以下 任意一条 要求:

  • 空字符串或只包含小写字母的字符串
  • 可以被写作 AB(A 连接 B)的字符串,其中 A 和 B 都是有效「括号字符串」
  • 可以被写作 (A) 的字符串,其中 A 是一个有效的「括号字符串」
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
string minRemoveToMakeValid(string s) {
stack<int> stk1;
stack<char> stk2;
for (int m = 0; m < s.size(); m++) {
if(s[m] == '(') {
stk1.push(m);
stk2.push(s[m]);
} else if(s[m] == ')') {
if (!stk2.empty() && stk2.top() == '(') {
stk1.pop();
stk2.pop();
} else {
stk1.push(m);
stk2.push(s[m]);
}
}
}
while(!stk1.empty()) {
s[stk1.top()] = '*';
stk1.pop();
}
string ans = "";
for (auto x : s) {
if (x != '*') {
ans += x;
}
}
return ans;
}
};

1234. 替换子串得到平衡字符串

问题地址:https://leetcode.cn/problems/replace-the-substring-for-balanced-string/

有一个只含有 'Q', 'W', 'E''R' 四种字符,且长度为 n 的字符串。

假如在该字符串中,这四个字符都恰好出现 n/4 次,那么它就是一个「平衡字符串」

给你一个这样的字符串 s,请通过「替换一个子串」的方式,使原字符串 s 变成一个「平衡字符串」

你可以用和「待替换子串」长度相同的 任何 其他字符串来完成替换。

请返回待替换子串的最小可能长度。

如果原字符串自身就是一个平衡字符串,则返回 0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
public:
int idx(const char& c) {
return c - 'A';
}
int balancedString(string s) {
vector<int> cnt(26);
for (auto c : s) {
cnt[idx(c)]++;
}
int partial = s.size() / 4;
int res = s.size();
auto check = [&]() {
if (cnt[idx('Q')] > partial || cnt[idx('W')] > partial \
|| cnt[idx('E')] > partial || cnt[idx('R')] > partial) {
return false;
}
return true;
};

if (check()) {
return 0;
}

for (int l = 0, r = 0; l < s.size(); l++) {
while (r < s.size() && !check()) {
cnt[idx(s[r])]--;
r++;
}
if (!check()) {
break;
}
res = min(res, r - l);
cnt[idx(s[l])]++;
}
return res;
}
};

2385. 感染二叉树需要的总时间

问题地址:https://leetcode.cn/problems/amount-of-time-for-binary-tree-to-be-infected/

给你一棵二叉树的根节点 root ,二叉树中节点的值 互不相同 。另给你一个整数 start 。在第 0 分钟,感染 将会从值为 start 的节点开始爆发。

每分钟,如果节点满足以下全部条件,就会被感染:

  • 节点此前还没有感染。
  • 节点与一个已感染节点相邻。

返回感染整棵树需要的分钟数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int dfs(TreeNode* root, int start, int sum) {
if (root == nullptr) return -1;
if (sum == -1 && root->val == start) { // 本节点为感染节点
sum = 0;
}
if (sum != -1) { // 本节点已感染,传递到子树中
dfs(root->left, start, sum+1);
dfs(root->right, start, sum+1);
if (sum > max) max = sum;
return sum + 1;
} else {
int tem = dfs(root->left, start, sum);
if (tem != -1) { // 左子树被感染,传递到右子树
sum = tem;
dfs(root->right, start, sum+1);
} else { // 右子树被感染,传递到左子树
sum = dfs(root->right, start, sum);
dfs(root->left, start, sum+1);
}
}
if (sum > max) max = sum;
if (sum != -1) return sum + 1;
return -1;
}
int amountOfTime(TreeNode * root, int start) {
dfs(root, start, -1);
return max;
}

private:
int max = 0;
};

面试题 05.04. 下一个数

问题地址:https://leetcode.cn/problems/closed-number-lcci/

下一个数。给定一个正整数,找出与其二进制表达式中1的个数相同且大小最接近的那两个数(一个略大,一个略小)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {
public:
vector<int> findClosedNumbers(int num) {
bitset<32> small(num);
bitset<32> bigger(num);

int s = -1;
// small, 10 转 01,1移到左侧
for (int i = 1; i < 32; i++) {
if (small[i] == 1 && small[i - 1] == 0) {
small.flip(i);
small.flip(i - 1);
for (int left = 0, right = i - 2; left < right;) {
while (left < right && small[left] == 0) left++;
while (left < right && small[right] == 1) right--;
small.flip(left);
small.flip(right);
}
s = (int)small.to_ulong();
break;
}
}

// bigger, 01转10,1移到最右侧
// bigger要保证正数,最高符号位保证为 0
int b = -1;
for (int i = 1; i < 31; i++) {
if (bigger[i] == 0 && bigger[i - 1] == 1) {
bigger.flip(i);
bigger.flip(i - 1);

for (int left = 0, right = i - 2; left < right;) {
while (left < right && bigger[left] == 1) left++;
while (left < right && bigger[right] == 0) right--;
bigger.flip(left);
bigger.flip(right);
}
b = (int)bigger.to_ulong();
break;
}
}

return {b, s};
}
};

712. 两个字符串的最小ASCII删除和

问题地址:https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/

给定两个字符串s1 和 s2,返回 使两个字符串相等所需删除字符的 ASCII 值的最小和 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
int m = s1.size();
int n = s2.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));

for (int i = 1; i <= m; ++i) {
dp[i][0] = dp[i - 1][0] + s1[i - 1];
}

for (int j = 1; j <= n; ++j) {
dp[0][j] = dp[0][j - 1] + s2[j - 1];
}

for (int i = 1; i <= m; i++) {
char c1 = s1[i - 1];
for (int j = 1; j <= n; j++) {
char c2 = s2[j - 1];
if (c1 == c2) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1]);
}
}
}

return dp[m][n];
}
};

1253. 重构 2 行二进制矩阵

问题地址:https://leetcode.cn/problems/reconstruct-a-2-row-binary-matrix/

给你一个 2 行 n 列的二进制数组:

  • 矩阵是一个二进制矩阵,这意味着矩阵中的每个元素不是 0 就是 1。
  • 第 0 行的元素之和为 upper。
  • 第 1 行的元素之和为 lower。
  • 第 i 列(从 0 开始编号)的元素之和为 colsum[i],colsum 是一个长度为 n 的整数数组。

你需要利用 upper,lower 和 colsum 来重构这个矩阵,并以二维整数数组的形式返回它。

如果有多个不同的答案,那么任意一个都可以通过本题。

如果不存在符合要求的答案,就请返回一个空的二维数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
vector<vector<int>> reconstructMatrix(int upper, int lower, vector<int>& colsum) {
int n = colsum.size();
int sum = 0, two = 0;
for (int i = 0; i < n; ++i) {
if (colsum[i] == 2) {
++two;
}
sum += colsum[i];
}
if (sum != upper + lower || min(upper, lower) < two) {
return {};
}
upper -= two;
lower -= two;
vector<vector<int>> res(2, vector<int>(n, 0));
for (int i = 0; i < n; ++i) {
if (colsum[i] == 2) {
res[0][i] = res[1][i] = 1;
} else if (colsum[i] == 1) {
if (upper > 0) {
res[0][i] = 1;
--upper;
} else {
res[1][i] = 1;
}
}
}
return res;
}
};

229. 多数元素 II

问题地址:https://leetcode.cn/problems/majority-element-ii/

给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
int n = nums.size();
vector<int> ans;
unordered_map<int, int> cnt;

for (auto & v : nums) {
cnt[v]++;
}

for (auto & v : cnt) {
if (v.second > n /3) {
ans.push_back(v.first);
}
}

return ans;
}
};

1870. 准时到达的列车最小时速

给你一个浮点数 hour ,表示你到达办公室可用的总通勤时间。要到达办公室,你必须按给定次序乘坐 n 趟列车。另给你一个长度为 n 的整数数组 dist ,其中 dist[i] 表示第 i 趟列车的行驶距离(单位是千米)。

每趟列车均只能在整点发车,所以你可能需要在两趟列车之间等待一段时间。

  • 例如,第 1 趟列车需要 1.5 小时,那你必须再等待 0.5 小时,搭乘在第 2 小时发车的第 2 趟列车。

返回能满足你准时到达办公室所要求全部列车的 最小正整数 时速(单位:千米每小时),如果无法准时到达,则返回 -1 。

生成的测试用例保证答案不超过 107 ,且 hour 的 小数点后最多存在两位数字 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
int minSpeedOnTime(vector<int>& dist, double hour) {
int n = dist.size();
// 将 hour 乘 100 以转为整数
long long hr = llround(hour * 100);
// 时间必须要大于路程段数减 1
if (hr <= (n - 1) * 100){
return -1;
}
// 二分
int l = 1;
int r = 1e7;
while (l < r){
int mid = l + (r - l) / 2;
// 判断当前时速是否满足时限
long long t = 0;
for (int i = 0; i < n - 1; ++i){
t += (dist[i] - 1) / mid + 1;
}
t *= mid;
t += dist[n-1];
if (t * 100 <= hr * mid){ // 通分以转化为整数比较
r = mid;
}
else{
l = mid + 1;
}
}
return l; // 满足条件的最小时速
}
};

1864. 构成交替字符串需要的最小交换次数

问题地址:https://leetcode.cn/problems/minimum-number-of-swaps-to-make-the-binary-string-alternating/

给你一个二进制字符串 s ,现需要将其转化为一个 交替字符串 。请你计算并返回转化所需的 最小 字符交换次数,如果无法完成转化,返回 -1 。

交替字符串 是指:相邻字符之间不存在相等情况的字符串。例如,字符串 “010” 和 “1010” 属于交替字符串,但 “0100” 不是。

任意两个字符都可以进行交换,不必相邻 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int minSwaps(string s) {
int s0n0 = 0, s0n1 = 0;
int s1n0 = 0, s1n1 = 0;

for (int c = 0; c < s.size(); c++) {
if (c % 2 == 0) {
if (s[c] != '0') s0n0++;
else s1n1++;
} else {
if (s[c] != '1') s0n1++;
else s1n0++;
}
}

if (s0n0 != s0n1 && s1n0 != s1n1) return -1;
if (s0n0 == s0n1 && s1n0 != s1n1) return s0n0;
if (s0n0 != s0n1 && s1n0 == s1n1) return s1n0;
return min(s0n0, s1n0);
}
};

3. 无重复字符的最长子串

问题地址:https://leetcode.cn/problems/longest-substring-without-repeating-characters/

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> occ;
int n = s.size();
int rk = -1, ans = 0;
for (int i = 0; i < n; ++i) {
if (i != 0) {
occ.erase(s[i - 1]);
}
while (rk + 1 < n && !occ.count(s[rk + 1])) {
occ.insert(s[rk + 1]);
++rk;
}
ans = max(ans, rk - i + 1);
}
return ans;
}
};

5. 最长回文子串

问题地址:https://leetcode.cn/problems/longest-palindromic-substring/

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
string longestPalindrome(string s) {
int start = 0, end = 0;
for (int i = 0; i < s.size(); ++i) {
auto [left1, right1] = expandAroundCenter(s, i, i);
auto [left2, right2] = expandAroundCenter(s, i, i + 1);
if (right1 - left1 > end - start) {
start = left1;
end = right1;
}
if (right2 - left2 > end - start) {
start = left2;
end = right2;
}
}
return s.substr(start, end - start + 1);
}
pair<int, int> expandAroundCenter(const string& s, int left, int right) {
while (left >= 0 && right < s.size() && s[left] == s[right]) {
--left;
++right;
}
return {left + 1, right - 1};
}
};

6. N 字形变换

问题地址:https://leetcode.cn/problems/zigzag-conversion/

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:

1
2
3
P   A   H   N
A P L S I I G
Y I R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。

请你实现这个将字符串进行指定行数变换的函数:

1
string convert(string s, int numRows);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
string convert(string s, int numRows) {
int n = s.length(), r = numRows;
if (r == 1 || r >= n) {
return s;
}
vector<string> mat(r);
for (int i = 0, x = 0, t = r * 2 - 2; i < n; ++i) {
mat[x] += s[i];
i % t < r - 1 ? ++x : --x;
}
string ans;
for (auto &row : mat) {
ans += row;
}
return ans;
}
};

7. 整数反转

问题地址:https://leetcode.cn/problems/reverse-integer/

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int reverse(int x) {
int rev = 0;
while (x != 0) {
if (rev < INT_MIN / 10 || rev > INT_MAX / 10) {
return 0;
}
int digit = x % 10;
x /= 10;
rev = rev * 10 + digit;
}
return rev;
}
};

8. 字符串转换整数 (atoi)

问题地址:https://leetcode.cn/problems/string-to-integer-atoi/

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−231,  231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
  6. 返回整数作为最终结果。

注意:

  • 本题中的空白字符只包括空格字符 ’ ’ 。
  • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int myAtoi(string s) {
if (s.empty()) return 0;
int index = 0, n = s.size(), sign = 1, res = 0;
while (index < n && s[index] == ' ') {
++index;
}
if (index < n && (s[index] == '+' || s[index] == '-')) {
sign = s[index++] == '+' ? 1 : -1;
}
while (index < n && isdigit(s[index])) {
int digit = s[index] - '0';
if (res > (INT_MAX - digit) / 10) {
return sign == 1 ? INT_MAX : INT_MIN;
}
res = res * 10 + digit;
++index;
}
return res * sign;
}
};

11. 盛最多水的容器

问题地址:https://leetcode.cn/problems/container-with-most-water/

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int maxArea(vector<int>& height) {
int i = 0, j = height.size() - 1, res = 0;
while (i < j) {
res = height[i] < height[j] ?
max(res, (j - i) * height[i++]):
max(res, (j - i) * height[j--]);
}
return res;
}
};

12. 整数转罗马数字

问题地址:https://leetcode.cn/problems/integer-to-roman/

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

1
2
3
4
5
6
7
8
字符          数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给你一个整数,将其转为罗马数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const pair<int, string> valueSymbols[] = {
{1000, "M"},
{900, "CM"},
{500, "D"},
{400, "CD"},
{100, "C"},
{90, "XC"},
{50, "L"},
{40, "XL"},
{10, "X"},
{9, "IX"},
{5, "V"},
{4, "IV"},
{1, "I"},
};

class Solution {
public:
string intToRoman(int num) {
string roman;
for (const auto &[value, symbol] : valueSymbols) {
while (num >= value) {
num -= value;
roman += symbol;
}
if (num == 0) {
break;
}
}
return roman;
}
};

15. 三数之和

问题地址:https://leetcode.cn/problems/3sum/

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
if (size < 3) return {};
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for (int i = 0; i < size; i++)
{
if (nums[i] > 0) return res;
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1;
int right = size - 1;
while (left < right) {
if (nums[left] + nums[right] + nums[i] > 0) {
right--;
} else if (nums[left] + nums[right] + nums[i] < 0) {
left++;
} else {
res.push_back(vector<int>{nums[i], nums[left], nums[right]});
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) left++;
while (left < right && nums[right] == nums[right + 1]) right--;
}
}
}
return res;
}
};

16. 最接近的三数之和

问题地址:https://leetcode.cn/problems/3sum-closest/

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int n = nums.size();
int best = 1e7;

auto update = [&](int cur) {
if (abs(cur - target) < abs(best - target)) {
best = cur;
}
};

for (int i = 0; i < n; ++i) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int j = i + 1, k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
if (sum == target) {
return target;
}
update(sum);
if (sum > target) {
int k0 = k - 1;
while (j < k0 && nums[k0] == nums[k]) {
--k0;
}
k = k0;
} else {
int j0 = j + 1;
while (j0 < k && nums[j0] == nums[j]) {
++j0;
}
j = j0;
}
}
}

return best;
}
};

17. 电话号码的字母组合

问题地址:https://leetcode.cn/problems/letter-combinations-of-a-phone-number/

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> combinations;
if (digits.empty()) {
return combinations;
}
unordered_map<char, string> phoneMap{
{'2', "abc"},
{'3', "def"},
{'4', "ghi"},
{'5', "jkl"},
{'6', "mno"},
{'7', "pqrs"},
{'8', "tuv"},
{'9', "wxyz"}
};
string combination;
backtrack(combinations, phoneMap, digits, 0, combination);
return combinations;
}

void backtrack(vector<string>& combinations,
const unordered_map<char, string>& phoneMap,
const string& digits,
int index,
string& combination) {
if (index == digits.length()) {
combinations.push_back(combination);
} else {
char digit = digits[index];
const string& letters = phoneMap.at(digit);
for (const char& letter : letters) {
combination.push_back(letter);
backtrack(combinations, phoneMap, digits, index + 1, combination);
combination.pop_back();
}
}
}
};

18. 四数之和

问题地址:https://leetcode.cn/problems/4sum/

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> quadruplets;
if (nums.size() < 4) {
return quadruplets;
}
sort(nums.begin(), nums.end());
int length = nums.size();
for (int i = 0; i < length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for (int j = i + 1; j < length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] >target) {
break;
}
if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
quadruplets.push_back({nums[i], nums[j], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return quadruplets;
}
};

19. 删除链表的倒数第 N 个结点

问题地址:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
int getLength(ListNode * head) {
int length = 0;
while (head) {
++length;
head = head->next;
}
return length;
}
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode * dummy = new ListNode(0, head);
int length = getLength(head);
ListNode * cur = dummy;
for (int i = 1; i < length - n + 1; ++i) {
cur = cur->next;
}
cur->next = cur->next->next;
ListNode * ans = dummy->next;
delete dummy;
return ans;
}
};

22. 括号生成

问题地址:https://leetcode.cn/problems/generate-parentheses/

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> result;
string current;
backtrack(result, current, 0, 0, n);
return result;
}
void backtrack(vector<string>& ans, string& cur, int open, int close, int n) {
if (cur.size() == n * 2) {
ans.push_back(cur);
return;
}
if (open < n) {
cur.push_back('(');
backtrack(ans, cur, open + 1, close, n);
cur.pop_back();
}
if (close < open) {
cur.push_back(')');
backtrack(ans, cur, open, close + 1, n);
cur.pop_back();
}
}
};

24. 两两交换链表中的节点

问题地址:https://leetcode.cn/problems/swap-nodes-in-pairs/

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* temp = dummyHead;
while (temp->next != nullptr && temp->next->next != nullptr) {
ListNode* node1 = temp->next;
ListNode* node2 = temp->next->next;
temp->next = node2;
node1->next = node2->next;
node2->next = node1;
temp = node1;
}
return dummyHead->next;
}
};

204. 计数质数

问题地址:https://leetcode.cn/problems/count-primes/

给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int countPrimes(int n) {
vector<int> isPrime(n, 1);
int ans = 0;
for (int i = 2; i < n; ++i) {
if (isPrime[i]) {
ans += 1;
if ((long long)i * i < n) {
for (int j = i * i; j < n; j += i) {
isPrime[j] = 0;
}
}
}
}
return ans;
}
};

2761. 和等于目标值的质数对

问题地址:https://leetcode.cn/problems/prime-pairs-with-target-sum/

给你一个整数 n 。如果两个整数 x 和 y 满足下述条件,则认为二者形成一个质数对:

  • 1 <= x <= y <= n
  • x + y == n
  • x 和 y 都是质数

请你以二维有序列表的形式返回符合题目要求的所有 [xi, yi] ,列表需要按 xi 的 非递减顺序 排序。如果不存在符合要求的质数对,则返回一个空数组。

注意:质数是大于 1 的自然数,并且只有两个因子,即它本身和 1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
vector<vector<int>> findPrimePairs(int n) {
vector<bool> isPrime(n, true);
for (int i = 2; i < n; i++) {
if (isPrime[i]) {
for (int j = i; j < n; j += i) {
if (j != i) isPrime[j] = false;
}
}
}
vector<vector<int>> ret;
for (int i = 2; i <= n -i; i++) {
if (isPrime[i] && isPrime[n - i]) {
ret.push_back({i, n - i});
}
}
return ret;
}
};

2762. 不间断子数组

问题地址:https://leetcode.cn/problems/continuous-subarrays/

给你一个下标从 0 开始的整数数组 nums 。nums 的一个子数组如果满足以下条件,那么它是 不间断 的:

  • i,i + 1 ,…,j  表示子数组中的下标。对于所有满足 i <= i1i_1, i2i_2 <= j 的下标对,都有 0 <= |nums[i1i_1] - nums[i2i_2]| <= 2 。

请你返回 不间断 子数组的总数目。

子数组是一个数组中一段连续 非空 的元素序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
long long continuousSubarrays(vector<int>& nums) {
long long ans = 0;
multiset<int> s;
int left = 0, n = nums.size();
for (int right = 0; right < n; right++) {
s.insert(nums[right]);
while (*s.rbegin() - *s.begin() > 2) {
s.erase(s.find(nums[left++]));
}
ans += right - left + 1;
}
return ans;
}
};

2. 两数相加

问题地址:https://leetcode.cn/problems/add-two-numbers/

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode * head = nullptr, * tail = nullptr;
int carry = 0;
while (l1 || l2) {
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
int sum = n1 + n2 + carry;
if (!head) {
head = tail = new ListNode(sum % 10);
} else {
tail->next = new ListNode(sum % 10);
tail = tail->next;
}
carry = sum / 10;
if (l1) {
l1 = l1->next;
}
if (l2) {
l2 = l2->next;
}
}
if (carry > 0) {
tail->next = new ListNode(carry);
}
return head;
}
};

445. 两数相加 II

问题地址:https://leetcode.cn/problems/add-two-numbers-ii/

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
stack<int> s1, s2;
while (l1) {
s1.push(l1->val);
l1 = l1->next;
}
while (l2) {
s2.push(l2->val);
l2 = l2->next;
}
int carry = 0;
ListNode * ans = nullptr;
while (!s1.empty() or !s2.empty() or carry != 0) {
int a = s1.empty() ? 0 : s1.top();
int b = s2.empty() ? 0 : s2.top();
if (!s1.empty()) s1.pop();
if (!s2.empty()) s2.pop();
int cur = a + b + carry;
carry = cur / 10;
cur %= 10;
auto curnode = new ListNode(cur);
curnode->next = ans;
ans = curnode;
}
return ans;
}
};

2679. 矩阵中的和

问题地址:https://leetcode.cn/problems/sum-in-a-matrix/

给你一个下标从 0 开始的二维整数数组 nums 。一开始你的分数为 0 。你需要执行以下操作直到矩阵变为空:

  • 矩阵中每一行选取最大的一个数,并删除它。如果一行中有多个最大的数,选择任意一个并删除。
  • 在步骤 1 删除的所有数字中找到最大的一个数字,将它添加到你的 分数 中。

请你返回最后的 分数 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int matrixSum(vector<vector<int>>& nums) {
int res = 0;
int m = nums.size();
int n = nums[0].size();
for (int i = 0; i < m; i++) {
sort(nums[i].begin(), nums[i].end());
}
for (int j = 0; j < n; j++) {
int maxVal = 0;
for (int i = 0; i < m; i++) {
maxVal = max(maxVal, nums[i][j]);
}
res += maxVal;
}
return res;
}
};

29. 两数相除

问题地址:https://leetcode.cn/problems/divide-two-integers/

给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。

整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8 ,-2.7335 将被截断至 -2 。

返回被除数 dividend 除以除数 divisor 得到的 商 。

注意:假设我们的环境只能存储 32 位 有符号整数,其数值范围是 [−231,  231 − 1] 。本题中,如果商 严格大于 231 − 1 ,则返回 231 − 1 ;如果商 严格小于 -231 ,则返回 -231 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
int divide(int dividend, int divisor) {
if (dividend == 0) return 0;
if (divisor == 1) return dividend;
if (divisor == -1) {
if (dividend > INT_MIN) return -dividend;
return INT_MAX;
}
long a = dividend;
long b = divisor;
int sign = 1;
if ((a > 0 && b < 0) || (a < 0 && b > 0)) {
sign = -1;
}
a = a > 0 ? a : -a;
b = b > 0 ? b : -b;
long res = div(a, b);
if (sign > 0) return res > INT_MAX ? INT_MAX : res;
return -res;
}
int div(long a, long b) {
if (a < b) return 0;
long count = 1;
long tb = b;
while ((tb + tb) <= a) {
count = count + count;
tb = tb + tb;
}
return count + div(a - tb, b);
}
};

2178. 拆分成最多数目的正偶数之和

问题地址:https://leetcode.cn/problems/maximum-split-of-positive-even-integers/

给你一个整数 finalSum 。请你将它拆分成若干个 互不相同 的正偶数之和,且拆分出来的正偶数数目 最多 。

  • 比方说,给你 finalSum = 12 ,那么这些拆分是 符合要求 的(互不相同的正偶数且和为 finalSum):(2 + 10) ,(2 + 4 + 6) 和 (4 + 8) 。它们中,(2 + 4 + 6) 包含最多数目的整数。注意 finalSum 不能拆分成 (2 + 2 + 4 + 4) ,因为拆分出来的整数必须互不相同。

请你返回一个整数数组,表示将整数拆分成 最多 数目的正偶数数组。如果没有办法将 finalSum 进行拆分,请你返回一个 空 数组。你可以按 任意 顺序返回这些整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
vector<long long> maximumEvenSplit(long long finalSum) {
vector<long long> res;
if (finalSum % 2 > 0) {
return res;
}
for (int i = 2; i <= finalSum; i += 2) {
res.push_back(i);
finalSum -= i;
}
res.back() += finalSum;
return res;
}
};

31. 下一个排列

问题地址:https://leetcode.cn/problems/next-permutation/

整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。

  • 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。

整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

  • 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
  • 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
  • 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。

给你一个整数数组 nums ,找出 nums 的下一个排列。

必须 原地 修改,只允许使用额外常数空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = nums.size() - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
};

33. 搜索旋转排序数组

问题地址:https://leetcode.cn/problems/search-in-rotated-sorted-array/

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
if (!n) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
if (nums[0] <= nums[mid]) {
if (nums[0] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
};

979. 在二叉树中分配硬币

问题地址:https://leetcode.cn/problems/distribute-coins-in-binary-tree/

给你一个有 n 个结点的二叉树的根结点 root ,其中树中每个结点 node 都对应有 node.val 枚硬币。整棵树上一共有 n 枚硬币。

在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。移动可以是从父结点到子结点,或者从子结点移动到父结点。

返回使每个结点上 只有 一枚硬币所需的 最少 移动次数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int distributeCoins(TreeNode* root) {
int move = 0;

function<int(const TreeNode *)> dfs = [&](const TreeNode * root) -> int {
int moveleft = 0;
int moveright = 0;
if (root == nullptr) {
return 0;
}
if (root->left) {
moveleft = dfs(root->left);
}
if (root->right) {
moveright = dfs(root->right);
}
move += abs(moveleft) + abs(moveright);
return moveleft + moveright + root->val - 1;
};

dfs(root);
return move;
}
};

36. 有效的数独

问题地址:https://leetcode.cn/problems/valid-sudoku/

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 空白格用 ‘.’ 表示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
int rows[9][9];
int columns[9][9];
int subboxes[3][3][9];

memset(rows,0,sizeof(rows));
memset(columns,0,sizeof(columns));
memset(subboxes,0,sizeof(subboxes));
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char c = board[i][j];
if (c != '.') {
int index = c - '0' - 1;
rows[i][index]++;
columns[j][index]++;
subboxes[i / 3][j / 3][index]++;
if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[i / 3][j / 3][index] > 1) {
return false;
}
}
}
}
return true;
}
};

34. 在排序数组中查找元素的第一个和最后一个位置

问题地址:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution { 
public:
int binarySearch(vector<int>& nums, int target, bool lower) {
int left = 0, right = (int)nums.size() - 1, ans = (int)nums.size();
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid - 1;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}

vector<int> searchRange(vector<int>& nums, int target) {
int leftIdx = binarySearch(nums, target, true);
int rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) {
return vector<int>{leftIdx, rightIdx};
}
return vector<int>{-1, -1};
}
};

38. 外观数列

问题地址:https://leetcode.cn/problems/count-and-say/

给定一个正整数 n ,输出外观数列的第 n 项。

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

你可以将其视作是由递归公式定义的数字字符串序列:

  • countAndSay(1) = “1”
  • countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。

前五项如下:

1
2
3
4
5
6
7
8
9
10
1.     1
2. 11
3. 21
4. 1211
5. 111221
第一项是数字 1
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"

要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
string countAndSay(int n) {
string prev = "1";
for (int i = 2; i <= n; ++i) {
string curr = "";
int start = 0;
int pos = 0;
while (pos < prev.size()) {
while (pos < prev.size() && prev[pos] == prev[start]) {
pos++;
}
curr += to_string(pos - start) + prev[start];
start = pos;
}
prev = curr;
}
return prev;
}
};

80. 删除有序数组中的重复项 II

问题地址:https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = nums.size();
if (n <= 2) {
return n;
}
int slow = 2, fast = 2;
while (fast < n) {
if (nums[slow - 2] != nums[fast]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
};

189. 轮转数组

问题地址:https://leetcode.cn/problems/rotate-array/

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
vector<int> newArr(n);
for (int i = 0; i < n; ++i) {
newArr[(i + k) % n] = nums[i];
}
nums.assign(newArr.begin(), newArr.end());
}
};

122. 买卖股票的最佳时机 II

问题地址:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
int n = prices.size();
for (int i = 1; i < n; ++i) {
ans += max(0, prices[i] - prices[i - 1]);
}
return ans;
}
};

55. 跳跃游戏

问题地址:https://leetcode.cn/problems/jump-game/

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
bool canJump(vector<int>& nums) {
int n = nums.size();
int rightmost = 0;
for (int i = 0; i < n; ++i) {
if (i <= rightmost) {
rightmost = max(rightmost, i + nums[i]);
if (rightmost >= n - 1) {
return true;
}
}
}
return false;
}
};

45. 跳跃游戏 II

问题地址:https://leetcode.cn/problems/jump-game-ii/

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i]
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int jump(vector<int>& nums) {
int maxPos = 0, n = nums.size(), end = 0, step = 0;
for (int i = 0; i < n - 1; ++i) {
if (maxPos >= i) {
maxPos = max(maxPos, i + nums[i]);
if (i == end) {
end = maxPos;
++step;
}
}
}
return step;
}
};

274. H 指数

问题地址:https://leetcode.cn/problems/h-index/

给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。

根据维基百科上 h 指数的定义:h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且每篇论文 至少 被引用 h 次。如果 h 有多种可能的值,h 指数 是其中最大的那个。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int hIndex(vector<int>& citations) {
sort(citations.begin(), citations.end());
int h = 0, i = citations.size() - 1;
while (i >= 0 && citations[i] > h) {
h++;
i--;
}
return h;
}
};

380. O(1) 时间插入、删除和获取随机元素

问题地址:https://leetcode.cn/problems/insert-delete-getrandom-o1/

实现RandomizedSet 类:

  • RandomizedSet() 初始化 RandomizedSet 对象
  • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。
  • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false 。
  • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。

你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1) 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class RandomizedSet {
private:
vector<int> nums;
unordered_map<int, int> indices;
public:
RandomizedSet() {
srand((unsigned)time(nullptr));
}

bool insert(int val) {
if (indices.count(val)) {
return false;
}
int index = nums.size();
nums.emplace_back(val);
indices[val] = index;
return true;
}

bool remove(int val) {
if (!indices.count(val)) {
return false;
}
int index = indices[val];
int last = nums.back();
nums[index] = last;
indices[last] = index;
nums.pop_back();
indices.erase(val);
return true;
}

int getRandom() {
int randomIndex = rand() % nums.size();
return nums[randomIndex];
}
};

/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet* obj = new RandomizedSet();
* bool param_1 = obj->insert(val);
* bool param_2 = obj->remove(val);
* int param_3 = obj->getRandom();
*/

238. 除自身以外数组的乘积

问题地址:https://leetcode.cn/problems/product-of-array-except-self/

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

请 不要使用除法,且在 O(n) 时间复杂度内完成此题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length = nums.size();
vector<int> L(length, 0), R(length, 0);
vector<int> answer(length);
L[0] = 1;
for (int i = 1; i < length; i++) {
L[i] = nums[i - 1] * L[i - 1];
}
R[length - 1] = 1;
for (int i = length - 2; i >= 0; i--) {
R[i] = nums[i + 1] * R[i + 1];
}
for (int i = 0; i < length; i++) {
answer[i] = L[i] * R[i];
}
return answer;
}
};

134. 加油站

问题地址:https://leetcode.cn/problems/gas-station/

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gas 和 cost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int n = gas.size();
int i = 0;
while (i < n) {
int sumOfGas = 0, sumOfCost = 0;
int cnt = 0;
while (cnt < n) {
int j = (i + cnt) % n;
sumOfGas += gas[j];
sumOfCost += cost[j];
if (sumOfCost > sumOfGas) {
break;
}
cnt++;
}
if (cnt == n) {
return i;
} else {
i = i + cnt + 1;
}
}
return -1;
}
};

151. 反转字符串中的单词

问题地址:https://leetcode.cn/problems/reverse-words-in-a-string/

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
string reverseWords(string s) {
reverse(s.begin(), s.end());
int n = s.size();
int idx = 0;
for (int start = 0; start < n; ++start) {
if (s[start] != ' ') {
if (idx != 0) s[idx++] = ' ';
int end = start;
while (end < n && s[end] != ' ') s[idx++] = s[end++];
reverse(s.begin() + idx - (end - start), s.begin() + idx);
start = end;
}
}
s.erase(s.begin() + idx, s.end());
return s;
}
};

53. 最大子数组和

问题地址:https://leetcode.cn/problems/maximum-subarray/

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0, maxAns = nums[0];
for (const auto &x : nums) {
pre = max(pre + x, x);
maxAns = max(maxAns, pre);
}
return maxAns;
}
};

167. 两数之和 II - 输入有序数组

问题地址:https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
for (int i = 0; i < numbers.size(); ++i) {
int low = i + 1, high = numbers.size() - 1;
while (low <= high) {
int mid = (high - low) / 2 + low;
if (numbers[mid] == target - numbers[i]) {
return {i + 1, mid + 1};
} else if (numbers[mid] > target - numbers[i]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
}
return {-1, -1};
}
};

209. 长度最小的子数组

问题地址:https://leetcode.cn/problems/minimum-size-subarray-sum/

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int ans = INT_MAX;
int start = 0, end = 0;
int sum = 0;
while (end < n) {
sum += nums[end];
while (sum >= target) {
ans = min(ans, end - start + 1);
sum -= nums[start];
start++;
}
end++;
}
return ans == INT_MAX ? 0 : ans;
}
};

54. 螺旋矩阵

问题地址:https://leetcode.cn/problems/spiral-matrix/

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if (matrix.size() == 0 || matrix[0].size() == 0) {
return {};
}
int rows = matrix.size(), columns = matrix[0].size();
vector<int> order;
int left = 0, right = columns - 1, top = 0, bottom = rows - 1;
while (left <= right && top <= bottom) {
for (int column = left; column <= right; column++) {
order.push_back(matrix[top][column]);
}
for (int row = top + 1; row <= bottom; row++) {
order.push_back(matrix[row][right]);
}
if (left < right && top < bottom) {
for (int column = right - 1; column > left; column--) {
order.push_back(matrix[bottom][column]);
}
for (int row = bottom; row > top; row--) {
order.push_back(matrix[row][left]);
}
}
left++;
right--;
top++;
bottom--;
}
return order;
}
};

48. 旋转图像

问题地址:https://leetcode.cn/problems/rotate-image/

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < (n + 1) / 2; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = temp;
}
}
}
};

73. 矩阵置零

问题地址:https://leetcode.cn/problems/set-matrix-zeroes/

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<int> row(m), col(n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (!matrix[i][j]) {
row[i] = col[j] = true;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (row[i] || col[j]) {
matrix[i][j] = 0;
}
}
}
}
};

289. 生命游戏

问题地址:https://leetcode.cn/problems/game-of-life/

根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。

给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态: 1 即为 活细胞 (live),或 0 即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:

  1. 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
  2. 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
  3. 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
  4. 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;

下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。给你 m x n 网格面板 board 的当前状态,返回下一个状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
int neighbors[3] = {0, 1, -1};
int rows = board.size();
int cols = board[0].size();

vector<vector<int>> copyBoard(rows, vector<int>(cols, 0));

for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
copyBoard[row][col] = board[row][col];
}
}

for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
int liveNeighbors = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (!(neighbors[i] == 0 && neighbors[j] == 0)) {
int r = (row + neighbors[i]);
int c = (col + neighbors[j]);

if ((r < rows && r >= 0) && (c < cols && c >=0) && (copyBoard[r][c] == 1)) {
liveNeighbors += 1;
}
}
}
}

if ((copyBoard[row][col] == 1) && (liveNeighbors < 2 || liveNeighbors > 3)) {
board[row][col] = 0;
}
if (copyBoard[row][col] == 0 && liveNeighbors == 3) {
board[row][col] = 1;
}
}
}
}
};

128. 最长连续序列

问题地址:https://leetcode.cn/problems/longest-consecutive-sequence/

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> num_set;
for (const int& num : nums) {
num_set.insert(num);
}
int longestStreak = 0;
for (const int& num : num_set) {
if (!num_set.count(num - 1)) {
int currentNum = num;
int currentStreak = 1;

while (num_set.count(currentNum + 1)) {
currentNum += 1;
currentStreak += 1;
}

longestStreak = max(longestStreak, currentStreak);
}
}
return longestStreak;
}
};

49. 字母异位词分组

问题地址:https://leetcode.cn/problems/group-anagrams/

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
for (string& str : strs) {
string key = str;
sort(key.begin(), key.end());
mp[key].emplace_back(str);
}
vector<vector<string>> ans;
for (auto it = mp.begin(); it != mp.end(); ++it) {
ans.emplace_back(it->second);
}
return ans;
}
};

56. 合并区间

问题地址:https://leetcode.cn/problems/merge-intervals/

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if (intervals.size() == 0) {
return {};
}
sort(intervals.begin(), intervals.end());
vector<vector<int>> merged;
for (int i = 0; i < intervals.size(); ++i) {
int L = intervals[i][0], R = intervals[i][1];
if (!merged.size() || merged.back()[1] < L) {
merged.push_back({L, R});
} else {
merged.back()[1] = max(merged.back()[1], R);
}
}
return merged;
}
};

57. 插入区间

问题地址:https://leetcode.cn/problems/insert-interval/

给你一个 无重叠的 ,按照区间起始端点排序的区间列表。

在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
int left = newInterval[0];
int right = newInterval[1];
bool placed = false;
vector<vector<int>> ans;
for (const auto& interval : intervals) {
if (interval[0] > right) {
if (!placed) {
ans.push_back({left, right});
placed = true;
}
ans.push_back(interval);
}
else if (interval[1] < left) {
ans.push_back(interval);
} else {
left = min(left,interval[0]);
right = max(right, interval[1]);
}
}
if (!placed) {
ans.push_back({left, right});
}
return ans;
}
};

452. 用最少数量的箭引爆气球

问题地址:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。

给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty()) {
return 0;
}
sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>& v) {
return u[1] < v[1];
});
int pos = points[0][1];
int ans = 1;
for (const vector<int>& balloon : points) {
if (balloon[0] > pos) {
pos = balloon[1];
++ans;
}
}
return ans;
}
};

71. 简化路径

问题地址:https://leetcode.cn/problems/simplify-path/

给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 ‘/’ 开头),请你将其转化为更加简洁的规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,‘//’)都被视为单个斜杠 ‘/’ 。 对于此问题,任何其他格式的点(例如,‘…’)均被视为文件/目录名称。

请注意,返回的 规范路径 必须遵循下述格式:

  • 始终以斜杠 ‘/’ 开头。
  • 两个目录名之间必须只有一个斜杠 ‘/’ 。
  • 最后一个目录名(如果存在)不能 以 ‘/’ 结尾。
  • 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 ‘.’ 或 ‘…’)。

返回简化后得到的 规范路径 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
public:
string simplifyPath(string path) {
auto split = [](const string& s, char delim) -> vector<string> {
vector<string> ans;
string cur;
for (char ch : s) {
if (ch == delim) {
ans.push_back(move(cur));
cur.clear();
} else {
cur += ch;
}
}
ans.push_back(move(cur));
return ans;
};
vector<string> names = split(path, '/');
vector<string> stack;
for (string& name : names) {
if (name == "..") {
if (!stack.empty()) {
stack.pop_back();
}
} else if (!name.empty() && name != ".") {
stack.push_back(move(name));
}
}
string ans;
if (stack.empty()) {
ans = "/";
} else {
for (string& name : stack) {
ans += "/" + move(name);
}
}
return ans;
}
};

155. 最小栈

问题地址:https://leetcode.cn/problems/min-stack/

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class MinStack {
stack<int> x_stack;
stack<int> min_stack;
public:
MinStack() {
min_stack.push(INT_MAX);
}

void push(int val) {
x_stack.push(val);
min_stack.push(min(min_stack.top(), val));
}

void pop() {
x_stack.pop();
min_stack.pop();
}

int top() {
return x_stack.top();
}

int getMin() {
return min_stack.top();
}
};

/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/

150. 逆波兰表达式求值

问题地址:https://leetcode.cn/problems/evaluate-reverse-polish-notation/

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> stk;
int n = tokens.size();
for (int i = 0; i < n; i++) {
string& token = tokens[i];
if (isNumber(token)) {
stk.push(atoi(token.c_str()));
} else {
int num2 = stk.top();
stk.pop();
int num1 = stk.top();
stk.pop();
switch (token[0]) {
case '+':
stk.push(num1 + num2);
break;
case '-':
stk.push(num1 - num2);
break;
case '*':
stk.push(num1 * num2);
break;
case '/':
stk.push(num1 / num2);
break;
}
}
}
return stk.top();
}

bool isNumber(string& token) {
return !(token == "+" || token == "-" || token == "*" || token == "/");
}
};

138. 随机链表的复制

问题地址:https://leetcode.cn/problems/copy-list-with-random-pointer/

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

你的代码 只 接受原链表的头节点 head 作为传入参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;

Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/

class Solution {
public:
unordered_map<Node*, Node*> cachedNode;
Node* copyRandomList(Node* head) {
if (head == nullptr) {
return nullptr;
}
if (!cachedNode.count(head)) {
Node* headNew = new Node(head->val);
cachedNode[head] = headNew;
headNew->next = copyRandomList(head->next);
headNew->random = copyRandomList(head->random);
}
return cachedNode[head];
}
};

221. 最大正方形

问题地址:https://leetcode.cn/problems/maximal-square/

在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.size() == 0 || matrix[0].size() == 0) {
return 0;
}
int maxSide = 0;
int rows = matrix.size(), columns = matrix[0].size();
vector<vector<int>> dp(rows, vector<int>(columns));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if (matrix[i][j] == '1') {
if (i == 0 || j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
}
maxSide = max(maxSide, dp[i][j]);
}
}
}
int maxSquare = maxSide * maxSide;
return maxSquare;
}
};

92. 反转链表 II

问题地址:https://leetcode.cn/problems/reverse-linked-list-ii/

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode *dummyNode = new ListNode(-1);
dummyNode->next = head;

ListNode * pre = dummyNode;
for (int i = 0; i < left - 1; i++) {
pre = pre->next;
}
ListNode *rightNode = pre;
for (int i = 0; i < right - left + 1; i++) {
rightNode = rightNode->next;
}
ListNode *leftNode = pre->next;
ListNode *curr = rightNode->next;

pre->next = nullptr;
rightNode->next = nullptr;

reverseLinkedList(leftNode);

pre->next = rightNode;
leftNode->next = curr;
return dummyNode->next;
}

void reverseLinkedList(ListNode *head) {
ListNode *pre = nullptr;
ListNode *cur = head;

while (cur != nullptr) {
ListNode *next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
}
};

82. 删除排序链表中的重复元素 II

问题地址:https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (!head) {
return head;
}
ListNode* dummy = new ListNode(0, head);
ListNode* cur = dummy;
while (cur->next && cur->next->next) {
if (cur->next->val == cur->next->next->val) {
int x = cur->next->val;
while (cur->next && cur->next->val == x) {
cur->next = cur->next->next;
}
} else {
cur = cur->next;
}
}
return dummy->next;
}
};

61. 旋转链表

问题地址:https://leetcode.cn/problems/rotate-list/

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (k == 0 || head == nullptr || head->next == nullptr) {
return head;
}
int n = 1;
ListNode* iter = head;
while (iter->next != nullptr) {
iter = iter->next;
n++;
}
int add = n - k % n;
if (add == n) {
return head;
}
iter->next = head;
while (add--) {
iter = iter->next;
}
ListNode* ret = iter->next;
iter->next = nullptr;
return ret;
}
};

146. LRU 缓存

问题地址:https://leetcode.cn/problems/lru-cache/

请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
struct DLinkedNode {
int key, value;
DLinkedNode* prev;
DLinkedNode* next;
DLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr) {}
DLinkedNode(int _key, int _value): key(_key), value(_value), prev(nullptr), next(nullptr) {}
};

class LRUCache {
private:
unordered_map<int, DLinkedNode*> cache;
DLinkedNode* head;
DLinkedNode* tail;
int size;
int capacity;
public:
LRUCache(int _capacity): capacity(_capacity), size(0) {
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);
++size;
if (size > capacity) {
DLinkedNode* removed = removeTail();
cache.erase(removed->key);
delete removed;
--size;
}
} else {
DLinkedNode* node = cache[key];
node->value = value;
moveToHead(node);
}
}

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;
}
};

/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/

105. 从前序与中序遍历序列构造二叉树

问题地址:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
unordered_map<int, int> index;
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
for (int i = 0; i < n; ++i) {
index[inorder[i]] = i;
}
return build_tree(preorder, inorder, 0, n - 1, 0, n - 1);
}
TreeNode* build_tree(const vector<int>& preorder, const vector<int>& inorder,
int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
if (preorder_left > preorder_right) {
return nullptr;
}
int preorder_root = preorder_left;
int inorder_root = index[preorder[preorder_root]];
TreeNode* root = new TreeNode(preorder[preorder_root]);
int size_left_subtree = inorder_root - inorder_left;
root->left = build_tree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree,
inorder_left, inorder_root - 1);
root->right = build_tree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right,
inorder_root + 1, inorder_right);
return root;
}
};

106. 从中序与后序遍历序列构造二叉树

问题地址:https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
int post_idx;
unordered_map<int, int> idx_map;
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
post_idx = (int)postorder.size() - 1;
int idx = 0;
for (auto& val : inorder) {
idx_map[val] = idx++;
}
return helper(0, (int)inorder.size() - 1, inorder, postorder);
}
TreeNode* helper(int int_left, int in_right, vector<int>& inorder, vector<int>& postorder) {
if (int_left > in_right) {
return nullptr;
}
int root_val = postorder[post_idx];
TreeNode* root = new TreeNode(root_val);
int index = idx_map[root_val];
post_idx--;
root->right = helper(index + 1, in_right, inorder, postorder);
root->left = helper(int_left, index - 1, inorder, postorder);
return root;
}
};

117. 填充每个节点的下一个右侧节点指针 II

问题地址:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/

给定一个二叉树:

1
2
3
4
5
6
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。

初始状态下,所有 next 指针都被设置为 NULL 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;

Node() : val(0), left(NULL), right(NULL), next(NULL) {}

Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/

class Solution {
public:
Node* connect(Node* root) {
if (!root) return root;
queue<Node*> q;
q.push(root);
Node* last;
Node* node;
int size;
while (!q.empty()) {
size = q.size();
last = nullptr;
while (size-- > 0) {
node = q.front();
q.pop();
if (last) last->next = node;
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
last = node;
}
}
return root;
}
};

114. 二叉树展开为链表

问题地址:https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void flatten(TreeNode* root) {
vector<TreeNode*> l;
preorder(root, l);
int n = l.size();
for (int i = 1; i < n; i++) {
TreeNode *prev = l[i-1], *curr = l[i];
prev->left = nullptr;
prev->right = curr;
}
}
void preorder(TreeNode* root, vector<TreeNode*> &l) {
if (root != nullptr) {
l.push_back(root);
preorder(root->left, l);
preorder(root->right, l);
}
}
};

129. 求根节点到叶节点数字之和

问题地址:https://leetcode.cn/problems/sum-root-to-leaf-numbers/

给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:

  • 例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。

计算从根节点到叶节点生成的 所有数字之和 。

叶节点 是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int sumNumbers(TreeNode* root) {
return dfs(root, 0);
}
int dfs(TreeNode* root, int preSum) {
if (root == nullptr) {
return 0;
}
int sum = preSum * 10 + root->val;
if (root->left == nullptr && root->right == nullptr) {
return sum;
} else {
return dfs(root->left, sum) + dfs(root->right, sum);
}
}
};

173. 二叉搜索树迭代器

问题地址:https://leetcode.cn/problems/binary-search-tree-iterator/

实现一个二叉搜索树迭代器类BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器:

  • BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在于 BST 中的数字,且该数字小于 BST 中的任何元素。
  • boolean hasNext() 如果向指针右侧遍历存在数字,则返回 true ;否则返回 false 。
  • int next()将指针向右移动,然后返回指针处的数字。

注意,指针初始化为一个不存在于 BST 中的数字,所以对 next() 的首次调用将返回 BST 中的最小元素。

你可以假设 next() 调用总是有效的,也就是说,当调用 next() 时,BST 的中序遍历中至少存在一个下一个数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class BSTIterator {
private:
void inorder(TreeNode* root, vector<int>& res) {
if (!root) {
return;
}
inorder(root->left, res);
res.push_back(root->val);
inorder(root->right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
inorder(root, res);
return res;
}
vector<int> arr;
int idx;
public:
BSTIterator(TreeNode* root): idx(0), arr(inorderTraversal(root)) {}

int next() {
return arr[idx++];
}

bool hasNext() {
return (idx < arr.size());
}
};

/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator* obj = new BSTIterator(root);
* int param_1 = obj->next();
* bool param_2 = obj->hasNext();
*/

236. 二叉树的最近公共祖先

问题地址:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
TreeNode* ans;
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) return false;
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if ((lson && rson) || ((root->val == p->val || root-> val == q->val) && (lson || rson))) {
ans = root;
}
return lson || rson || root->val == p->val || root->val == q->val;
}
};

199. 二叉树的右视图

问题地址:https://leetcode.cn/problems/binary-tree-right-side-view/

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> ans;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty()) {
int n = q.size();
while (n--) {
if (q.front()->left) q.push(q.front()->left);
if (q.front()->right) q.push(q.front()->right);
if (n == 0) ans.push_back(q.front()->val);
q.pop();
}
}
return ans;
}
};

102. 二叉树的层序遍历

问题地址:https://leetcode.cn/problems/binary-tree-level-order-traversal/

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ret;
if (!root) {
return ret;
}
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
auto n = q.size();
ret.push_back(vector<int>());
while (n--) {
auto node = q.front(); q.pop();
ret.back().push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
return ret;
}
};

103. 二叉树的锯齿形层序遍历

问题地址:https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> ans;
if (!root) {
return ans;
}
queue<TreeNode*> q;
q.push(root);
bool left = true;
while (!q.empty()) {
deque<int> list;
int n = q.size();
while (n--) {
auto node = q.front();
q.pop();
if (left) {
list.push_back(node->val);
} else {
list.push_front(node->val);
}
if (node->left) {
q.push(node->left);
}
if (node->right) {
q.push(node->right);
}
}
ans.emplace_back(vector<int>{list.begin(), list.end()});
left = !left;
}
return ans;
}
};

230. 二叉搜索树中第K小的元素

问题地址:https://leetcode.cn/problems/kth-smallest-element-in-a-bst/

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
vector<int> ans;
public:
int kthSmallest(TreeNode* root, int k) {
dfs(root);
return ans[k - 1];
}
void dfs(TreeNode* root) {
if (root == nullptr) return;
dfs(root->left);
ans.push_back(root->val);
dfs(root->right);
}
};

98. 验证二叉搜索树

问题地址:https://leetcode.cn/problems/validate-binary-search-tree/

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
return helper(root, LONG_MIN, LONG_MAX);
}
bool helper(TreeNode* root, long long lower, long long upper) {
if (root == nullptr) return true;
if (root->val <= lower || root->val >= upper) {
return false;
}
return helper(root->left, lower, root->val) && helper(root->right, root->val, upper);
}
};

200. 岛屿数量

问题地址:https://leetcode.cn/problems/number-of-islands/

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
private:
int r, c;
void dfs(vector<vector<char>>& grid, int i, int j) {
grid[i][j] = '0';
if (i - 1 >= 0 && grid[i-1][j] == '1') dfs(grid, i - 1, j);
if (i + 1 < r && grid[i+1][j] == '1') dfs(grid, i + 1, j);
if (j - 1 >= 0 && grid[i][j-1] == '1') dfs(grid, i, j - 1);
if (j + 1 < c && grid[i][j+1] == '1') dfs(grid, i, j + 1);
}

public:
int numIslands(vector<vector<char>>& grid) {
r = grid.size();
if (!r) return 0;
c = grid[0].size();

int num = 0;
for (int i = 0; i < r; ++i) {
for (int j = 0; j < c; ++j) {
if (grid[i][j] == '1') {
++num;
dfs(grid, i, j);
}
}
}

return num;
}
};

130. 被围绕的区域

问题地址:https://leetcode.cn/problems/surrounded-regions/

给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution {
public:
int n, m;

void dfs(vector<vector<char>>& board, int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m || board[x][y] != 'O') {
return;
}
board[x][y] = 'A';
dfs(board, x + 1, y);
dfs(board, x - 1, y);
dfs(board, x, y + 1);
dfs(board, x, y - 1);
}

void solve(vector<vector<char>>& board) {
n = board.size();
if (n == 0) {
return;
}
m = board[0].size();
for (int i = 0; i < n; i++) {
dfs(board, i, 0);
dfs(board, i, m - 1);
}
for (int i = 1; i < m - 1; i++) {
dfs(board, 0, i);
dfs(board, n - 1, i);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (board[i][j] == 'A') {
board[i][j] = 'O';
} else if (board[i][j] == 'O') {
board[i][j] = 'X';
}
}
}
}
};

133. 克隆图

问题地址:https://leetcode.cn/problems/clone-graph/

给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。

图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。

1
2
3
4
class Node {
public int val;
public List<Node> neighbors;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/

class Solution {
private:
unordered_map<Node*, Node*> visited;
public:
Node* cloneGraph(Node* node) {
if (node == nullptr) {
return node;
}
if (visited.find(node) != visited.end()) {
return visited[node];
}
Node* clone = new Node(node->val);
visited[node] = clone;
for (auto& neighbor : node->neighbors) {
clone->neighbors.emplace_back(cloneGraph(neighbor));
}
return clone;
}
};

148. 排序链表

问题地址:https://leetcode.cn/problems/sort-list/

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
return sortList(head, nullptr);
}
ListNode* sortList(ListNode* head, ListNode* tail) {
if (head == nullptr) {
return head;
}
if (head->next == tail) {
head->next = nullptr;
return head;
}
ListNode* slow = head, *fast = head;
while (fast != tail) {
slow = slow->next;
fast = fast->next;
if (fast != tail) {
fast = fast->next;
}
}
ListNode* mid = slow;
return merge(sortList(head, mid), sortList(mid, tail));
}
ListNode* merge(ListNode* head1, ListNode* head2) {
ListNode* dummyHead = new ListNode(0);
ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;
while (temp1 != nullptr && temp2 != nullptr) {
if (temp1->val <= temp2->val) {
temp->next = temp1;
temp1 = temp1->next;
} else {
temp->next = temp2;
temp2 = temp2->next;
}
temp = temp->next;
}
if (temp1 != nullptr) {
temp->next = temp1;
} else if (temp2 != nullptr) {
temp->next = temp2;
}
return dummyHead->next;
}
};

74. 搜索二维矩阵

问题地址:https://leetcode.cn/problems/search-a-2d-matrix/

给你一个满足下述两条属性的 m x n 整数矩阵:

  • 每行中的整数从左到右按非严格递增顺序排列。
  • 每行的第一个整数大于前一行的最后一个整数。

给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
auto row = upper_bound(matrix.begin(), matrix.end(), target, [](const int target, const vector<int> &matrix) {
return target < matrix[0];
});
if (row == matrix.begin()) {
return false;
}
--row;
return binary_search(row->begin(), row->end(), target);
}
};

162. 寻找峰值

问题地址:https://leetcode.cn/problems/find-peak-element/

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

1
2
3
4
5
6
class Solution {
public:
int findPeakElement(vector<int>& nums) {
return max_element(nums.begin(), nums.end()) - nums.begin();
}
};

399. 除法求值

问题地址:https://leetcode.cn/problems/evaluate-division/

给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。

另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。

返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。

注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

注意:未在等式列表中出现的变量是未定义的,因此无法确定它们的答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Solution {
public:
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
int nvars = 0;
unordered_map<string, int> variables;

int n = equations.size();
for (int i = 0; i < n; i++) {
if (variables.find(equations[i][0]) == variables.end()) {
variables[equations[i][0]] = nvars++;
}
if (variables.find(equations[i][1]) == variables.end()) {
variables[equations[i][1]] = nvars++;
}
}

// 对于每个点,存储其直接连接到的所有点及对应的权值
vector<vector<pair<int, double>>> edges(nvars);
for (int i = 0; i < n; i++) {
int va = variables[equations[i][0]], vb = variables[equations[i][1]];
edges[va].push_back(make_pair(vb, values[i]));
edges[vb].push_back(make_pair(va, 1.0 / values[i]));
}

vector<double> ret;
for (const auto& q: queries) {
double result = -1.0;
if (variables.find(q[0]) != variables.end() && variables.find(q[1]) != variables.end()) {
int ia = variables[q[0]], ib = variables[q[1]];
if (ia == ib) {
result = 1.0;
} else {
queue<int> points;
points.push(ia);
vector<double> ratios(nvars, -1.0);
ratios[ia] = 1.0;

while (!points.empty() && ratios[ib] < 0) {
int x = points.front();
points.pop();

for (const auto [y, val]: edges[x]) {
if (ratios[y] < 0) {
ratios[y] = ratios[x] * val;
points.push(y);
}
}
}
result = ratios[ib];
}
}
ret.push_back(result);
}
return ret;
}
};

207. 课程表

问题地址:https://leetcode.cn/problems/course-schedule/

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
private:
vector<vector<int>> edges;
vector<int> visited;
bool valid = true;
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
for (const auto& info : prerequisites) {
edges[info[1]].push_back(info[0]);
}
for (int i=0; i < numCourses && valid; ++i) {
if (!visited[i]) {
dfs(i);
}
}
return valid;
}
void dfs(int u) {
visited[u] = 1;
for (int v : edges[u]) {
if (visited[v] == 0) {
dfs(v);
if (!valid) {
return;
}
} else if (visited[v] == 1) {
valid = false;
return;
}
}
visited[u] = 2;
}
};

210. 课程表 II

问题地址:https://leetcode.cn/problems/course-schedule-ii/

现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。

  • 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。

返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
private:
vector<vector<int>> edges;
vector<int> visited;
vector<int> result;
bool valid = true;
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
for (const auto& info : prerequisites) {
edges[info[1]].push_back(info[0]);
}
for (int i = 0; i < numCourses && valid; ++i) {
if (!visited[i]) {
dfs(i);
}
}
if (!valid) {
return {};
}
reverse(result.begin(), result.end());
return result;
}
void dfs(int u) {
visited[u] = 1;
for (int v : edges[u]) {
if (visited[v] == 0) {
dfs(v);
if (!valid) {
return;
}
} else if (visited[v] == 1) {
valid = false;
return;
}
}
visited[u] = 2;
result.push_back(u);
}
};

77. 组合

问题地址:https://leetcode.cn/problems/combinations/

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> ans;
vector<int> path;
function<void(int)> dfs = [&](int i) {
int d = k - path.size();
if (d == 0) {
ans.emplace_back(path);
return;
}
for (int j = i; j >= d; --j) {
path.push_back(j);
dfs(j-1);
path.pop_back();
}
};
dfs(n);
return ans;
}
};

373. 查找和最小的 K 对数字

问题地址:https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/

给定两个以 非递减顺序排列 的整数数组 nums1 和 nums2 , 以及一个整数 k 。

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。

请找到和最小的 k 个数对 (u1,v1),  (u2,v2)  …  (uk,vk) 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
auto cmp = [&nums1, &nums2](const pair<int, int> & a, const pair<int, int> & b) {
return nums1[a.first] + nums2[a.second] > nums1[b.first] + nums2[b.second];
};

int m = nums1.size();
int n = nums2.size();
vector<vector<int>> ans;
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> pq(cmp);
for (int i = 0; i < min(k, m); i++) {
pq.emplace(i, 0);
}
while (k-- > 0 && !pq.empty()) {
auto [x, y] = pq.top();
pq.pop();
ans.emplace_back(initializer_list<int>{nums1[x], nums2[y]});
if (y + 1 < n) {
pq.emplace(x, y + 1);
}
}

return ans;
}
};

909. 蛇梯棋

问题地址:https://leetcode.cn/problems/snakes-and-ladders/

给你一个大小为 n x n 的整数矩阵 board ,方格按从 1 到 n2 编号,编号遵循 转行交替方式 ,从左下角开始 (即,从 board[n - 1][0] 开始)每一行交替方向。

玩家从棋盘上的方格 1 (总是在最后一行、第一列)开始出发。

每一回合,玩家需要从当前方格 curr 开始出发,按下述要求前进:

  • 选定目标方格 next ,目标方格的编号符合范围 [curr + 1, min(curr + 6, n2)] 。
    • 该选择模拟了掷 六面体骰子 的情景,无论棋盘大小如何,玩家最多只能有 6 个目的地。
  • 传送玩家:如果目标方格 next 处存在蛇或梯子,那么玩家会传送到蛇或梯子的目的地。否则,玩家传送到目标方格 next 。
  • 当玩家到达编号 n2 的方格时,游戏结束。

r 行 c 列的棋盘,按前述方法编号,棋盘格中可能存在 “蛇” 或 “梯子”;如果 board[r][c] != -1,那个蛇或梯子的目的地将会是 board[r][c]。编号为 1 和 n2 的方格上没有蛇或梯子。

注意,玩家在每回合的前进过程中最多只能爬过蛇或梯子一次:就算目的地是另一条蛇或梯子的起点,玩家也 不能 继续移动。

  • 举个例子,假设棋盘是 [[-1,4],[-1,3]] ,第一次移动,玩家的目标方格是 2 。那么这个玩家将会顺着梯子到达方格 3 ,但 不能 顺着方格 3 上的梯子前往方格 4 。

返回达到编号为 n2 的方格所需的最少移动次数,如果不可能,则返回 -1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
public:
int snakesAndLadders(vector<vector<int>>& board) {
int n = board.size();
vector<int> vis(n*n+1);
queue<pair<int,int>> q;
q.emplace(1,0);
while (!q.empty()) {
auto p = q.front();
q.pop();
for (int i=1; i<=6; ++i) {
int nxt = p.first + i;
if (nxt > n*n) {
break;
}
auto rc = id2rc(nxt, n);
if (board[rc.first][rc.second] > 0) {
nxt = board[rc.first][rc.second];
}
if (nxt == n*n) {
return p.second + 1;
}
if (!vis[nxt]) {
vis[nxt] = true;
q.emplace(nxt, p.second + 1);
}
}
}
return -1;
}
pair<int, int> id2rc(int id, int n) {
int r = (id - 1) / n, c = (id - 1) % n;
if (r % 2 == 1) {
c = n - 1 - c;
}
return {n - 1 - r, c};
}
};

433. 最小基因变化

问题地址:https://leetcode.cn/problems/minimum-genetic-mutation/

基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 ‘A’、‘C’、‘G’ 和 ‘T’ 之一。

假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。

  • 例如,“AACCGGTT” --> “AACCGGTA” 就是一次基因变化。

另有一个基因库 bank 记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。(变化后的基因必须位于基因库 bank 中)

给你两个基因序列 start 和 end ,以及一个基因库 bank ,请你找出并返回能够使 start 变化为 end 所需的最少变化次数。如果无法完成此基因变化,返回 -1 。

注意:起始基因序列 start 默认是有效的,但是它并不一定会出现在基因库中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {
public:
int minMutation(string start, string end, vector<string>& bank) {
unordered_set<string> cnt;
unordered_set<string> visited;
char keys[4] = {'A', 'C', 'G', 'T'};
for (auto& w : bank) {
cnt.emplace(w);
}
if (start == end) {
return 0;
}
if (!cnt.count(end)) {
return -1;
}
queue<string> qu;
qu.emplace(start);
visited.emplace(start);
int step = 1;
while (!qu.empty()) {
int sz = qu.size();
for (int i=0; i<sz; i++) {
string curr = qu.front();
qu.pop();
for (int j=0; j<8; j++) {
for (int k=0; k<4; k++) {
if (keys[k] != curr[j]) {
string next = curr;
next[j] = keys[k];
if (!visited.count(next) && cnt.count(next)) {
if (next == end) {
return step;
}
qu.emplace(next);
visited.emplace(next);
}
}
}
}
}
step++;
}
return -1;
}
};

208. 实现 Trie (前缀树)

问题地址:https://leetcode.cn/problems/implement-trie-prefix-tree/

Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word 。
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Trie {
private:
vector<Trie*> children;
bool isEnd;

Trie* searchPrefix(string prefix) {
Trie* node = this;
for (char ch : prefix) {
ch -= 'a';
if (node->children[ch] == nullptr) {
return nullptr;
}
node = node->children[ch];
}
return node;
}
public:
Trie() : children(26), isEnd(false) {}

void insert(string word) {
Trie* node = this;
for (char ch : word) {
ch -= 'a';
if (node->children[ch] == nullptr) {
node->children[ch] = new Trie();
}
node = node->children[ch];
}
node->isEnd = true;
}

bool search(string word) {
Trie* node = this->searchPrefix(word);
return node != nullptr && node->isEnd;
}

bool startsWith(string prefix) {
return this->searchPrefix(prefix) != nullptr;
}
};

/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/

211. 添加与搜索单词 - 数据结构设计

问题地址:https://leetcode.cn/problems/design-add-and-search-words-data-structure/

请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。

实现词典类 WordDictionary :

  • WordDictionary() 初始化词典对象
  • void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
  • bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回  false 。word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
struct TrieNode {
vector<TrieNode *> child;
bool isEnd;
TrieNode() {
this->child = vector<TrieNode *>(26, nullptr);
this->isEnd = false;
}
};
void insert(TrieNode* root, const string& word) {
TrieNode* node = root;
for (auto c : word) {
if (node->child[c - 'a'] == nullptr) {
node->child[c - 'a'] = new TrieNode();
}
node = node->child[c - 'a'];
}
node->isEnd = true;
}
class WordDictionary {
private:
TrieNode* trie;
public:
WordDictionary() {
trie = new TrieNode();
}

void addWord(string word) {
insert(trie, word);
}

bool search(string word) {
return dfs(word, 0, trie);
}

bool dfs(const string& word, int index, TrieNode* node) {
if (index == word.size()) {
return node->isEnd;
}
char ch = word[index];
if (ch >= 'a' && ch <= 'z') {
TrieNode* child = node->child[ch - 'a'];
if (child != nullptr && dfs(word, index+1, child)) {
return true;
}
} else if (ch == '.') {
for (int i=0; i<26; i++) {
TrieNode* child = node->child[i];
if (child != nullptr && dfs(word, index+1, child)) {
return true;
}
}
}
return false;
}
};

/**
* Your WordDictionary object will be instantiated and called as such:
* WordDictionary* obj = new WordDictionary();
* obj->addWord(word);
* bool param_2 = obj->search(word);
*/

46. 全排列

问题地址:https://leetcode.cn/problems/permutations/

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
backtrack(res, nums, 0, nums.size());
return res;
}
void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len) {
if (first == len) {
res.emplace_back(output);
return;
}
for (int i=first; i<len; ++i) {
swap(output[i], output[first]);
backtrack(res, output, first+1, len);
swap(output[i], output[first]);
}
}
};

39. 组合总和

问题地址:https://leetcode.cn/problems/combination-sum/

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> ans;
vector<int> combine;
dfs(candidates, target, ans, combine, 0);
return ans;
}
void dfs(vector<int>& candidates, int target, vector<vector<int>>& ans,
vector<int>& combine, int idx) {
if (idx == candidates.size()) {
return;
}
if (target == 0) {
ans.emplace_back(combine);
return;
}
dfs(candidates, target, ans, combine, idx+1);
if (target - candidates[idx] >= 0) {
combine.emplace_back(candidates[idx]);
dfs(candidates, target-candidates[idx], ans, combine, idx);
combine.pop_back();
}
}
};

79. 单词搜索

问题地址:https://leetcode.cn/problems/word-search/

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
private:
int rows, cols;
bool dfs(vector<vector<char>>& board, string word, int i, int j, int k) {
if (i >= rows || i < 0 || j >= cols || j < 0 || board[i][j] != word[k]) return false;
if (k == word.size() - 1) return true;
board[i][j] = '\0';
bool res = dfs(board, word, i+1, j, k+1) || dfs(board, word, i-1, j, k+1) ||
dfs(board, word, i, j+1, k+1) || dfs(board, word, i, j-1, k+1);
board[i][j] = word[k];
return res;
}
public:
bool exist(vector<vector<char>>& board, string word) {
rows = board.size();
cols = board[0].size();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (dfs(board, word, i, j, 0)) return true;
}
}
return false;
}
};

427. 建立四叉树

问题地址:https://leetcode.cn/problems/construct-quad-tree/

给你一个 n * n 矩阵 grid ,矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。

你需要返回能表示矩阵 grid 的 四叉树 的根结点。

四叉树数据结构中,每个内部节点只有四个子节点。此外,每个节点都有两个属性:

  • val:储存叶子结点所代表的区域的值。1 对应 True,0 对应 False。注意,当 isLeaf 为 False 时,你可以把 True 或者 False 赋值给节点,两种值都会被判题机制 接受 。
  • isLeaf: 当这个节点是一个叶子结点时为 True,如果它有 4 个子节点则为 False 。
1
2
3
4
5
6
7
8
class Node {
public boolean val;
    public boolean isLeaf;
    public Node topLeft;
    public Node topRight;
    public Node bottomLeft;
    public Node bottomRight;
}

我们可以按以下步骤为二维区域构建四叉树:

  1. 如果当前网格的值相同(即,全为 0 或者全为 1),将 isLeaf 设为 True ,将 val 设为网格相应的值,并将四个子节点都设为 Null 然后停止。
  2. 如果当前网格的值不同,将 isLeaf 设为 False, 将 val 设为任意值,然后如下图所示,将当前网格划分为四个子网格。
  3. 使用适当的子网格递归每个子节点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
// Definition for a QuadTree node.
class Node {
public:
bool val;
bool isLeaf;
Node* topLeft;
Node* topRight;
Node* bottomLeft;
Node* bottomRight;

Node() {
val = false;
isLeaf = false;
topLeft = NULL;
topRight = NULL;
bottomLeft = NULL;
bottomRight = NULL;
}

Node(bool _val, bool _isLeaf) {
val = _val;
isLeaf = _isLeaf;
topLeft = NULL;
topRight = NULL;
bottomLeft = NULL;
bottomRight = NULL;
}

Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) {
val = _val;
isLeaf = _isLeaf;
topLeft = _topLeft;
topRight = _topRight;
bottomLeft = _bottomLeft;
bottomRight = _bottomRight;
}
};
*/

class Solution {
public:
Node* construct(vector<vector<int>>& grid) {
function<Node*(int, int, int, int)> dfs = [&](int r0, int c0, int r1, int c1) {
for (int i=r0; i<r1; ++i) {
for (int j=c0; j<c1; ++j) {
if (grid[i][j] != grid[r0][c0]) {
return new Node(
true,
false,
dfs(r0, c0, (r0+r1)/2, (c0+c1)/2),
dfs(r0, (c0+c1)/2, (r0+r1)/2, c1),
dfs((r0+r1)/2, c0, r1, (c0+c1)/2),
dfs((r0+r1)/2, (c0+c1)/2, r1, c1)
);
}
}
}
return new Node(grid[r0][c0], true);
};
return dfs(0,0,grid.size(),grid[0].size());
}
};

918. 环形子数组的最大和

问题地址:https://leetcode.cn/problems/maximum-sum-circular-subarray/

给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。

环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i + 1) % n] , nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。

子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], …, nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int n = nums.size();
int preMax = nums[0], maxRes = nums[0];
int preMin = nums[0], minRes = nums[0];
int sum = nums[0];
for (int i = 1; i < n; i++) {
preMax = max(preMax + nums[i], nums[i]);
maxRes = max(maxRes, preMax);
preMin = min(preMin + nums[i], nums[i]);
minRes = min(minRes, preMin);
sum += nums[i];
}
if (maxRes < 0) {
return maxRes;
} else {
return max(maxRes, sum - minRes);
}
}
};

153. 寻找旋转排序数组中的最小值

问题地址:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int findMin(vector<int>& nums) {
int low = 0;
int high = nums.size() - 1;
while (low < high) {
int privot = low + (high - low) / 2;
if (nums[privot] < nums[high]) {
high = privot;
} else {
low = privot + 1;
}
}
return nums[low];
}
};

137. 只出现一次的数字 II

问题地址:https://leetcode.cn/problems/single-number-ii/

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map<int, int> freq;
for(int num : nums) {
++freq[num];
}
int ans = 0;
for (auto [num, occ] : freq) {
if (occ == 1) {
ans = num;
break;
}
}
return ans;
}
};

201. 数字范围按位与

问题地址:https://leetcode.cn/problems/bitwise-and-of-numbers-range/

给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int rangeBitwiseAnd(int left, int right) {
int shift = 0;
while (left < right) {
left >>= 1;
right >>= 1;
++shift;
}
return left << shift;
}
};

172. 阶乘后的零

问题地址:https://leetcode.cn/problems/factorial-trailing-zeroes/

给定一个整数 n ,返回 n! 结果中尾随零的数量。

提示 n! = n * (n - 1) * (n - 2) * … * 3 * 2 * 1

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int trailingZeroes(int n) {
int ans = 0;
for (int i = 5; i <= n; i += 5) {
for (int x = i; x % 5 == 0; x /= 5) {
++ans;
}
}
return ans;
}
};

322. 零钱兑换

问题地址:https://leetcode.cn/problems/coin-change/

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int Max = amount + 1;
vector<int> dp(amount + 1, Max);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int j = 0; j < coins.size(); ++j) {
if (coins[j] <= i) {
dp[i] = min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
};

300. 最长递增子序列

问题地址:https://leetcode.cn/problems/longest-increasing-subsequence/

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
vector<int> dp(n, 0);
for (int i = 0; i < n; ++i) {
dp[i] = 1;
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};

97. 交错字符串

问题地址:https://leetcode.cn/problems/interleaving-string/

给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。

两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:

  • s = s1 + s2 + … + sn
  • t = t1 + t2 + … + tm
  • |n - m| <= 1
  • 交错 是 s1 + t1 + s2 + t2 + s3 + t3 + … 或者 t1 + s1 + t2 + s2 + t3 + s3 + …

注意:a + b 意味着字符串 a 和 b 连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
auto f = vector<vector<int>>(s1.size() + 1, vector<int>(s2.size() + 1, false));
int n = s1.size(), m = s2.size(), t = s3.size();
if (n + m != t) return false;
f[0][0] = true;
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
int p = i + j - 1;
if (i > 0) {
f[i][j] |= (f[i - 1][j] && s1[i - 1] == s3[p]);
}
if (j > 0) {
f[i][j] |= (f[i][j - 1] && s2[j - 1] == s3[p]);
}
}
}
return f[n][m];
}
};

120. 三角形最小路径和

问题地址:https://leetcode.cn/problems/triangle/

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<vector<int>> f(n, vector<int>(n));
f[0][0] = triangle[0][0];
for (int i = 1; i < n; ++i) {
f[i][0] = f[i - 1][0] + triangle[i][0];
for (int j = 1; j < i; ++j) {
f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j];
}
f[i][i] = f[i - 1][i - 1] + triangle[i][i];
}
return *min_element(f[n - 1].begin(), f[n - 1].end());
}
};

64. 最小路径和

问题地址:https://leetcode.cn/problems/minimum-path-sum/

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.size() == 0 || grid[0].size() == 0) return 0;
int rows = grid.size(), columns = grid[0].size();
auto dp = vector<vector<int>>(rows, vector<int>(columns));
dp[0][0] = grid[0][0];
for (int i = 1; i < rows; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for (int j = 1; j < columns; j++) {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
for (int i = 1; i < rows; i++) {
for (int j = 1; j < columns; j++) {
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[rows - 1][columns - 1];
}
};

63. 不同路径 II

问题地址:https://leetcode.cn/problems/unique-paths-ii/

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int n = obstacleGrid.size(), m = obstacleGrid.at(0).size();
vector <int> f(m);

f[0] = (obstacleGrid[0][0] == 0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (obstacleGrid[i][j] == 1) {
f[j] = 0;
continue;
}
if (j - 1 >= 0 && obstacleGrid[i][j - 1] == 0) {
f[j] += f[j - 1];
}
}
}

return f.back();
}
};

43. 字符串相乘

问题地址:https://leetcode.cn/problems/multiply-strings/

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
string multiply(string num1, string num2) {
if (num1 == "0" || num2 == "0") {
return "0";
}
int m = num1.size(), n = num2.size();
auto ansArr = vector<int>(m + n);
for (int i = m - 1; i >= 0; i--) {
int x = num1[i] - '0';
for (int j = n - 1; j >= 0; j--) {
int y = num2[j] - '0';
ansArr[i + j + 1] += x * y;
}
}
for (int i = m + n - 1; i > 0; i--) {
ansArr[i - 1] += ansArr[i] / 10;
ansArr[i] %= 10;
}
int index = ansArr[0] == 0 ? 1 : 0;
string ans;
while (index < m + n) {
ans.push_back(ansArr[index]);
index++;
}
for (auto &c : ans) {
c += '0';
}
return ans;
}
};

237. 删除链表中的节点

问题地址:https://leetcode.cn/problems/delete-node-in-a-linked-list/

有一个单链表的 head,我们想删除它其中的一个节点 node。

给你一个需要删除的节点 node 。你将 无法访问 第一个节点  head。

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

  • 给定节点的值不应该存在于链表中。
  • 链表中的节点数应该减少 1。
  • node 前面的所有值顺序相同。
  • node 后面的所有值顺序相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
};

235. 二叉搜索树的最近公共祖先

问题地址:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/

class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode* ancestor = root;
while (true) {
if (p->val < ancestor->val && q->val <ancestor->val) {
ancestor = ancestor->left;
} else if (p->val > ancestor->val && q->val > ancestor->val) {
ancestor = ancestor->right;
} else {
break;
}
}
return ancestor;
}
};

142. 环形链表 II

问题地址:https://leetcode.cn/problems/linked-list-cycle-ii/

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_set<ListNode *> visited;
while (head != nullptr) {
if (visited.count(head)) {
return head;
}
visited.insert(head);
head = head->next;
}
return nullptr;
}
};

62. 不同路径

问题地址:https://leetcode.cn/problems/unique-paths/

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> f(n, 1);
f[0] = 1;
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; j++) {
f[j] += f[j - 1];
}
}
return f.back();
}
};

59. 螺旋矩阵 II

问题地址:https://leetcode.cn/problems/spiral-matrix-ii/

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
int t = 0; // top
int b = n-1; // bottom
int l = 0; // left
int r = n-1; // right
vector<vector<int>> ans(n,vector<int>(n));
int k=1;
while(k<=n*n){
for(int i=l;i<=r;++i,++k) ans[t][i] = k;
++t;
for(int i=t;i<=b;++i,++k) ans[i][r] = k;
--r;
for(int i=r;i>=l;--i,++k) ans[b][i] = k;
--b;
for(int i=b;i>=t;--i,++k) ans[i][l] = k;
++l;
}
return ans;
}
};

89. 格雷编码

问题地址:https://leetcode.cn/problems/gray-code/

n 位格雷码序列 是一个由 2n 个整数组成的序列,其中:

  • 每个整数都在范围 [0, 2n - 1] 内(含 0 和 2n - 1)
  • 第一个整数是 0
  • 一个整数在序列中出现 不超过一次
  • 每对 相邻 整数的二进制表示 恰好一位不同 ,且
  • 第一个 和 最后一个 整数的二进制表示 恰好一位不同

给你一个整数 n ,返回任一有效的 n 位格雷码序列 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<int> grayCode(int n) {
vector<int> ret;
ret.push_back(0);
for (int i = 1; i <= n; i++) {
int m = ret.size();
for (int j = m - 1; j >= 0; j--) {
ret.push_back(ret[j] | (1 << (i - 1)));
}
}
return ret;
}
};

739. 每日温度

问题地址:https://leetcode.cn/problems/daily-temperatures/

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n = temperatures.size();
vector<int> ans(n);
stack<int> s;
for (int i = 0; i < n; ++i) {
while (!s.empty() && temperatures[i] > temperatures[s.top()]) {
int previousIndex = s.top();
ans[previousIndex] = i - previousIndex;
s.pop();
}
s.push(i);
}
return ans;
}
};

435. 无重叠区间

问题地址:https://leetcode.cn/problems/non-overlapping-intervals/

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.empty()) {
return 0;
}

sort(intervals.begin(), intervals.end(), [](const auto& u, const auto& v) {
return u[1] < v[1];
});

int n = intervals.size();
int right = intervals[0][1];
int ans = 1;
for (int i = 1; i < n; ++i) {
if (intervals[i][0] >= right) {
++ans;
right = intervals[i][1];
}
}
return n - ans;
}
};

334. 递增的三元子序列

问题地址:https://leetcode.cn/problems/increasing-triplet-subsequence/

给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。

如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int n = nums.size();
if (n < 3) {
return false;
}
vector<int> leftMin(n);
leftMin[0] = nums[0];
for (int i = 1; i < n; i++) {
leftMin[i] = min(leftMin[i - 1], nums[i]);
}
vector<int> rightMax(n);
rightMax[n - 1] = nums[n - 1];
for (int i = n - 2; i >= 0; i--) {
rightMax[i] = max(rightMax[i + 1], nums[i]);
}
for (int i = 1; i < n - 1; i++) {
if (nums[i] > leftMin[i - 1] && nums[i] < rightMax[i + 1]) {
return true;
}
}
return false;
}
};

443. 压缩字符串

问题地址:https://leetcode.cn/problems/string-compression/

给你一个字符数组 chars ,请使用下述算法压缩:

从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符 :

  • 如果这一组长度为 1 ,则将字符追加到 s 中。
  • 否则,需要向 s 追加字符,后跟这一组的长度。

压缩后得到的字符串 s 不应该直接返回 ,需要转储到字符数组 chars 中。需要注意的是,如果组长度为 10 或 10 以上,则在 chars 数组中会被拆分为多个字符。

请在 修改完输入数组后 ,返回该数组的新长度。

你必须设计并实现一个只使用常量额外空间的算法来解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int compress(vector<char>& chars) {
int n = chars.size();
int write = 0, left = 0;
for (int read = 0; read < n; read++) {
if (read == n - 1 || chars[read] != chars[read + 1]) {
chars[write++] = chars[read];
int num = read - left + 1;
if (num > 1) {
int anchor = write;
while (num > 0) {
chars[write++] = num % 10 + '0';
num /= 10;
}
reverse(&chars[anchor], &chars[write]);
}
left = read + 1;
}
}
return write;
}
};

1679. K 和数对的最大数目

问题地址:https://leetcode.cn/problems/max-number-of-k-sum-pairs/

给你一个整数数组 nums 和一个整数 k 。

每一步操作中,你需要从数组中选出和为 k 的两个整数,并将它们移出数组。

返回你可以对数组执行的最大操作数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int maxOperations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int left = 0, right = nums.size() - 1;
int count = 0;
while (left < right) {
if (nums[left] + nums[right] < k) {
left++;
} else if (nums[left] + nums[right] > k) {
right--;
} else {
right--;
left++;
count++;
}
}
return count;
}
};

1456. 定长子串中元音的最大数目

问题地址:https://leetcode.cn/problems/maximum-number-of-vowels-in-a-substring-of-given-length/

给你字符串 s 和整数 k 。

请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。

英文中的 元音字母 为(a, e, i, o, u)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int maxVowels(string s, int k) {
int n = s.size();
int vowel_count = 0;
for (int i = 0; i < k; ++i) {
vowel_count += isVowel(s[i]);
}
int ans = vowel_count;
for (int i = k; i < n; ++i) {
vowel_count += isVowel(s[i]) - isVowel(s[i - k]);
ans = max(ans, vowel_count);
}
return ans;
}
bool isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}
};

1004. 最大连续1的个数 III

问题地址:https://leetcode.cn/problems/max-consecutive-ones-iii/

给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int n = nums.size();
int left = 0, lsum = 0, rsum = 0;
int ans = 0;
for (int right = 0; right < n; ++right) {
rsum += 1 - nums[right];
while (lsum < rsum - k) {
lsum += 1 - nums[left];
++left;
}
ans = max(ans, right - left + 1);
}
return ans;
}
};

1493. 删掉一个元素以后全为 1 的最长子数组

问题地址:https://leetcode.cn/problems/longest-subarray-of-1s-after-deleting-one-element/

给你一个二进制数组 nums ,你需要从中删掉一个元素。

请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。

如果不存在这样的子数组,请返回 0 。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int longestSubarray(vector<int>& nums) {
int sum = 0, l = 0, r;
for (r = 0; r < nums.size(); r++) {
sum += nums[r];
if (sum < r - l) {
sum -= nums[l++];
}
}
return r - l - 1;
}
};

450. 删除二叉搜索树中的节点

问题地址:https://leetcode.cn/problems/delete-node-in-a-bst/

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

  1. 首先找到需要删除的节点;
  2. 如果找到了,删除它。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) {
return nullptr;
}
if (root->val > key) {
root->left = deleteNode(root->left, key);
return root;
}
if (root->val < key) {
root->right = deleteNode(root->right, key);
return root;
}
if (root->val == key) {
if (!root->left && !root->right) {
return nullptr;
}
if (!root->right) {
return root->left;
}
if (!root->left) {
return root->right;
}
TreeNode* successor = root->right;
while (successor->left) {
successor = successor->left;
}
root->right = deleteNode(root->right, successor->val);
successor->right = root->right;
successor->left = root->left;
return successor;
}
return root;
}
};

1657. 确定两个字符串是否接近

问题地址:https://leetcode.cn/problems/determine-if-two-strings-are-close/

如果可以使用以下操作从一个字符串得到另一个字符串,则认为两个字符串 接近 :

  • 操作 1:交换任意两个 现有 字符。例如,abcde -> aecdb
  • 操作 2:将一个 现有 字符的每次出现转换为另一个 现有 字符,并对另一个字符执行相同的操作。例如,aacabb -> bbcbaa(所有 a 转化为 b ,而所有的 b 转换为 a )

你可以根据需要对任意一个字符串多次使用这两种操作。

给你两个字符串,word1 和 word2 。如果 word1 和 word2 接近 ,就返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
bool closeStrings(string word1, string word2) {
vector<int> c1(26, 0), c2(26, 0);
for (char c : word1) c1[c - 'a']++;
for (char c : word2) c2[c - 'a']++;
for (int i = 0; i < 26; i++) {
if (c1[i] + c2[i] == 0) continue;
if (c1[i] == 0 || c2[i] == 0) return false;
}
sort(c1.begin(), c1.end());
sort(c2.begin(), c2.end());
for (int i = 0; i < 26; i++) {
if (c1[i] != c2[i]) return false;
}
return true;
}
};

2352. 相等行列对

问题地址:https://leetcode.cn/problems/equal-row-and-column-pairs/

给你一个下标从 0 开始、大小为 n x n 的整数矩阵 grid ,返回满足 Ri 行和 Cj 列相等的行列对 (Ri, Cj) 的数目。

如果行和列以相同的顺序包含相同的元素(即相等的数组),则认为二者是相等的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
private:
int n;
public:
int equalPairs(vector<vector<int>>& grid) {
int res = 0;
n = grid.size();
for (int row = 0; row < n; row++) {
for (int col = 0; col < n; col++) {
if (equal(row, col, grid)) {
res++;
}
}
}
return res;
}
bool equal(int row, int col, vector<vector<int>>& grid) {
for (auto i = 0; i < n; i++) {
if (grid[row][i] != grid[i][col]) {
return false;
}
}
return true;
}
};

2390. 从字符串中移除星号

问题地址:https://leetcode.cn/problems/removing-stars-from-a-string/

给你一个包含若干星号 * 的字符串 s 。

在一步操作中,你可以:

  • 选中 s 中的一个星号。
  • 移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。

返回移除 所有 星号之后的字符串。

注意:

  • 生成的输入保证总是可以执行题面中描述的操作。
  • 可以证明结果字符串是唯一的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
string removeStars(string s) {
stack<char> stack;
for (auto c : s) {
if (stack.empty()) {
stack.push(c);
continue;
}
if (c == '*') {
stack.pop();
} else {
stack.push(c);
}
}
string res;
while (!stack.empty()) {
res += stack.top();
stack.pop();
}
reverse(res.begin(), res.end());
return res;
}
};

735. 小行星碰撞

问题地址:https://leetcode.cn/problems/asteroid-collision/

给定一个整数数组 asteroids,表示在同一行的小行星。

对于数组中的每一个元素,其绝对值表示小行星的大小,正负表示小行星的移动方向(正表示向右移动,负表示向左移动)。每一颗小行星以相同的速度移动。

找出碰撞后剩下的所有小行星。碰撞规则:两个小行星相互碰撞,较小的小行星会爆炸。如果两颗小行星大小相同,则两颗小行星都会爆炸。两颗移动方向相同的小行星,永远不会发生碰撞。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<int> asteroidCollision(vector<int>& asteroids) {
vector<int> st;
for (auto aster : asteroids) {
bool alive = true;
while (alive && aster < 0 && !st.empty() && st.back() > 0) {
alive = st.back() < -aster;
if (st.back() <= -aster) {
st.pop_back();
}
}
if (alive) {
st.push_back(aster);
}
}
return st;
}
};

394. 字符串解码

问题地址:https://leetcode.cn/problems/decode-string/

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
string decodeString(string s) {
string res = "";
stack<int> nums;
stack<string> strs;
int num = 0;
int len = s.size();
for (int i = 0; i < len; ++i) {
if (s[i] >= '0' && s[i] <= '9') {
num = num * 10 + s[i] - '0';
} else if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')) {
res = res + s[i];
} else if (s[i] == '[') {
nums.push(num);
num = 0;
strs.push(res);
res = "";
} else {
int times = nums.top();
nums.pop();
for (int j = 0; j < times; ++j) {
strs.top() += res;
}
res = strs.top();
strs.pop();
}
}
return res;
}
};

649. Dota2 参议院

问题地址:https://leetcode.cn/problems/dota2-senate/

Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇)

Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的 一 项:

  • 禁止一名参议员的权利:参议员可以让另一位参议员在这一轮和随后的几轮中丧失 所有的权利 。
  • 宣布胜利:如果参议员发现有权利投票的参议员都是 同一个阵营的 ,他可以宣布胜利并决定在游戏中的有关变化。

给你一个字符串 senate 代表每个参议员的阵营。字母 ‘R’ 和 'D’分别代表了 Radiant(天辉)和 Dire(夜魇)。然后,如果有 n 个参议员,给定字符串的大小将是 n。

以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。

假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 “Radiant” 或 “Dire” 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
string predictPartyVictory(string senate) {
int n = senate.size();
queue<int> radiant, dire;
for (int i = 0; i < n; ++i) {
if (senate[i] == 'R') {
radiant.push(i);
} else {
dire.push(i);
}
}
while (!radiant.empty() && !dire.empty()) {
if (radiant.front() < dire.front()) {
radiant.push(radiant.front() + n);
} else {
dire.push(dire.front() + n);
}
radiant.pop();
dire.pop();
}
return !radiant.empty() ? "Radiant" : "Dire";
}
};

2095. 删除链表的中间节点

问题地址:https://leetcode.cn/problems/delete-the-middle-node-of-a-linked-list/

给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。

长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点(下标从 0 开始),其中 ⌊x⌋ 表示小于或等于 x 的最大整数。

  • 对于 n = 1、2、3、4 和 5 的情况,中间节点的下标分别是 0、1、1、2 和 2 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteMiddle(ListNode* head) {
if (head->next == nullptr) {
return nullptr;
}
ListNode* slow = head;
ListNode* fast = head;
ListNode* pre = nullptr;
while (fast && fast->next) {
fast = fast->next->next;
pre = slow;
slow = slow->next;
}
pre->next = pre->next->next;
return head;
}
};

2130. 链表最大孪生和

问题地址:https://leetcode.cn/problems/maximum-twin-sum-of-a-linked-list/

在一个大小为 n 且 n 为 偶数 的链表中,对于 0 <= i <= (n / 2) - 1 的 i ,第 i 个节点(下标从 0 开始)的孪生节点为第 (n-1-i) 个节点 。

  • 比方说,n = 4 那么节点 0 是节点 3 的孪生节点,节点 1 是节点 2 的孪生节点。这是长度为 n = 4 的链表中所有的孪生节点。

孪生和 定义为一个节点和它孪生节点两者值之和。

给你一个长度为偶数的链表的头节点 head ,请你返回链表的 最大孪生和 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
int pairSum(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head->next;
while (fast->next) {
slow = slow->next;
fast = fast->next->next;
}
ListNode* last = slow->next;
while (last->next) {
ListNode* cur = last->next;
last->next = cur->next;
cur->next = slow->next;
slow->next = cur;
}
int ans = 0;
ListNode* x = head;
ListNode* y = slow->next;
while (y) {
ans = max(ans, x->val + y->val);
x = x->next;
y = y->next;
}
return ans;
}
};

1448. 统计二叉树中好节点的数目

问题地址:https://leetcode.cn/problems/count-good-nodes-in-binary-tree/

给你一棵根为 root 的二叉树,请你返回二叉树中好节点的数目。

「好节点」X 定义为:从根到该节点 X 所经过的节点中,没有任何节点的值大于 X 的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int goodNodes(TreeNode* root) {
return dfs(root, INT_MIN);
}
int dfs(TreeNode* root, int path_max) {
if (root == nullptr) {
return 0;
}
int res = 0;
if (root->val >= path_max) {
res++;
path_max = root->val;
}
res += dfs(root->left, path_max) + dfs(root->right, path_max);
return res;
}
};

437. 路径总和 III

问题地址:https://leetcode.cn/problems/path-sum-iii/

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
unordered_map<long long, int> prefix;
public:
int pathSum(TreeNode* root, int targetSum) {
prefix[0] = 1;
return dfs(root, 0, targetSum);
}
int dfs(TreeNode* root, long long curr, int targetSum) {
if (!root) {
return 0;
}
int ret = 0;
curr += root->val;
if (prefix.count(curr - targetSum)) {
ret = prefix[curr - targetSum];
}
prefix[curr]++;
ret += dfs(root->left, curr, targetSum);
ret += dfs(root->right, curr, targetSum);
prefix[curr]--;
return ret;
}
};

1372. 二叉树中的最长交错路径

问题地址:https://leetcode.cn/problems/longest-zigzag-path-in-a-binary-tree/

给你一棵以 root 为根的二叉树,二叉树中的交错路径定义如下:

  • 选择二叉树中 任意 节点和一个方向(左或者右)。
  • 如果前进方向为右,那么移动到当前节点的的右子节点,否则移动到它的左子节点。
  • 改变前进方向:左变右或者右变左。
  • 重复第二步和第三步,直到你在树中无法继续移动。

交错路径的长度定义为:访问过的节点数目 - 1(单个节点的路径长度为 0 )。

请你返回给定树中最长 交错路径 的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
int maxAns;
public:
int longestZigZag(TreeNode* root) {
if (!root) return 0;
maxAns = 0;
dfs(root, 0, 0);
dfs(root, 1, 0);
return maxAns;
}
void dfs(TreeNode* o, bool dir, int len) {
maxAns = max(maxAns, len);
if (!dir) {
if (o->left) dfs(o->left, 1, len + 1);
if (o->right) dfs(o->right, 0, 1);
} else {
if (o->right) dfs(o->right, 0, len + 1);
if (o->left) dfs(o->left, 1, 1);
}
}
};

1161. 最大层内元素和

问题地址:https://leetcode.cn/problems/maximum-level-sum-of-a-binary-tree/

给你一个二叉树的根节点 root。设根节点位于二叉树的第 1 层,而根节点的子节点位于第 2 层,依此类推。

请返回层内元素之和 最大 的那几层(可能只有一层)的层号,并返回其中 最小 的那个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
vector<int> sum;
public:
int maxLevelSum(TreeNode* root) {
dfs(root, 0);
int ans = 0;
for (int i = 0; i < sum.size(); ++i) {
if (sum[i] > sum[ans]) {
ans = i;
}
}
return ans + 1;
}
void dfs(TreeNode* node, int level) {
if (level == sum.size()) {
sum.push_back(node->val);
} else {
sum[level] += node->val;
}
if (node->left) {
dfs(node->left, level + 1);
}
if (node->right) {
dfs(node->right, level + 1);
}
}
};

901. 股票价格跨度

问题地址:https://leetcode.cn/problems/online-stock-span/

设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。

当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。

  • 例如,如果未来 7 天股票的价格是 [100,80,60,70,60,75,85],那么股票跨度将是 [1,1,1,2,1,4,6] 。

实现 StockSpanner 类:

  • StockSpanner() 初始化类对象。
  • int next(int price) 给出今天的股价 price ,返回该股票当日价格的 跨度 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class StockSpanner {
private:
stack<pair<int, int>> stk;
int idx;
public:
StockSpanner() {
this->stk.emplace(-1, INT_MAX);
this->idx = -1;
}

int next(int price) {
idx++;
while (price >= stk.top().second) {
stk.pop();
}
int ret = idx - stk.top().first;
stk.emplace(idx, price);
return ret;
}
};

/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner* obj = new StockSpanner();
* int param_1 = obj->next(price);
*/

841. 钥匙和房间

问题地址:https://leetcode.cn/problems/keys-and-rooms/

有 n 个房间,房间按从 0 到 n - 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间。

当你进入一个房间,你可能会在里面找到一套不同的钥匙,每把钥匙上都有对应的房间号,即表示钥匙可以打开的房间。你可以拿上所有钥匙去解锁其他房间。

给你一个数组 rooms 其中 rooms[i] 是你进入 i 号房间可以获得的钥匙集合。如果能进入 所有 房间返回 true,否则返回 false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
private:
vector<int> vis;
int num;
public:
bool canVisitAllRooms(vector<vector<int>>& rooms) {
int n = rooms.size();
num = 0;
vis.resize(n);
dfs(rooms, 0);
return num == n;
}
void dfs(vector<vector<int>>& rooms, int x) {
vis[x] = true;
num++;
for (auto& it : rooms[x]) {
if (!vis[it]) {
dfs(rooms, it);
}
}
}
};

547. 省份数量

问题地址:https://leetcode.cn/problems/number-of-provinces/

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int cities = isConnected.size();
vector<int> visited(cities);
int provinces = 0;
for (int i = 0; i < cities; i++) {
if (!visited[i]) {
dfs(isConnected, visited, cities, i);
provinces++;
}
}
return provinces;
}
void dfs(vector<vector<int>>& isConnected, vector<int>& visited, int cities, int i) {
for (int j = 0; j < cities; j++) {
if (isConnected[i][j] == 1 && !visited[j]) {
visited[j] = 1;
dfs(isConnected, visited, cities, j);
}
}
}
};

1466. 重新规划路线

问题地址:https://leetcode.cn/problems/reorder-routes-to-make-all-paths-lead-to-the-city-zero/

n 座城市,从 0 到 n-1 编号,其间共有 n-1 条路线。因此,要想在两座不同城市之间旅行只有唯一一条路线可供选择(路线网形成一颗树)。去年,交通运输部决定重新规划路线,以改变交通拥堵的状况。

路线用 connections 表示,其中 connections[i] = [a, b] 表示从城市 a 到 b 的一条有向路线。

今年,城市 0 将会举办一场大型比赛,很多游客都想前往城市 0 。

请你帮助重新规划路线方向,使每个城市都可以访问城市 0 。返回需要变更方向的最小路线数。

题目数据 保证 每个城市在重新规划路线方向后都能到达城市 0 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
int minReorder(int n, vector<vector<int>>& connections) {
vector<vector<int>> conn_idx(n, vector<int>());
for (int i = 0; i < connections.size(); i++) {
conn_idx[connections[i][0]].push_back(i);
conn_idx[connections[i][1]].push_back(i);
}
vector<bool> vi(connections.size(), false);
int ans = 0;
queue<int> que;
que.push(0);
while (!que.empty()) {
auto q = que.front();
que.pop();
for (auto idx : conn_idx[q]) {
if (vi[idx]) continue;
vi[idx] = true;
int a = connections[idx][0];
int b = connections[idx][1];
ans += (a == q);
a = (a == q) ? b : a;
que.push(a);
}
}
return ans;
}
};

1926. 迷宫中离入口最近的出口

问题地址:https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze/

给你一个 m x n 的迷宫矩阵 maze (下标从 0 开始),矩阵中有空格子(用 ‘.’ 表示)和墙(用 ‘+’ 表示)。同时给你迷宫的入口 entrance ,用 entrance = [entrancerow, entrancecol] 表示你一开始所在格子的行和列。

每一步操作,你可以往 上,下,左 或者 右 移动一个格子。你不能进入墙所在的格子,你也不能离开迷宫。你的目标是找到离 entrance 最近 的出口。出口 的含义是 maze 边界 上的 空格子。entrance 格子 不算 出口。

请你返回从 entrance 到最近出口的最短路径的 步数 ,如果不存在这样的路径,请你返回 -1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
int m = maze.size();
int n = maze[0].size();
vector<int> dx = {1, 0, -1, 0};
vector<int> dy = {0, 1, 0, -1};
queue<tuple<int, int, int>> q;
q.emplace(entrance[0], entrance[1], 0);
maze[entrance[0]][entrance[1]] = '+';
while (!q.empty()) {
auto [cx, cy, d] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int nx = cx + dx[k];
int ny = cy + dy[k];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && maze[nx][ny] == '.') {
if (nx == 0 || nx == m - 1 || ny == 0 || ny == n - 1) {
return d + 1;
}
maze[nx][ny] = '+';
q.emplace(nx, ny, d + 1);
}
}
}
return -1;
}
};

2336. 无限集中的最小数字

问题地址:https://leetcode.cn/problems/smallest-number-in-infinite-set/

现有一个包含所有正整数的集合 [1, 2, 3, 4, 5, …] 。

实现 SmallestInfiniteSet 类:

  • SmallestInfiniteSet() 初始化 SmallestInfiniteSet 对象以包含 所有 正整数。
  • int popSmallest() 移除 并返回该无限集中的最小整数。
  • void addBack(int num) 如果正整数 num 不 存在于无限集中,则将一个 num 添加 到该无限集最后。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class SmallestInfiniteSet {
private:
set<int> s;
public:
SmallestInfiniteSet() {
s.clear();
for (int i = 1; i < 1001; i++) s.insert(i);
}

int popSmallest() {
int x = *s.begin();
s.erase(s.begin());
return x;
}

void addBack(int num) {
s.insert(num);
}
};

/**
* Your SmallestInfiniteSet object will be instantiated and called as such:
* SmallestInfiniteSet* obj = new SmallestInfiniteSet();
* int param_1 = obj->popSmallest();
* obj->addBack(num);
*/

1268. 搜索推荐系统

问题地址:https://leetcode.cn/problems/search-suggestions-system/

给你一个产品数组 products 和一个字符串 searchWord ,products  数组中每个产品都是一个字符串。

请你设计一个推荐系统,在依次输入单词 searchWord 的每一个字母后,推荐 products 数组中前缀与 searchWord 相同的最多三个产品。如果前缀相同的可推荐产品超过三个,请按字典序返回最小的三个。

请你以二维列表的形式,返回在输入 searchWord 每个字母后相应的推荐产品的列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
sort(products.begin(), products.end());
int n = products.size();
vector<vector<string>> ans;
for (int i = 0; i < searchWord.length(); i++) {
string cur = searchWord.substr(0, i + 1);
int l = 0, r = n - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (products[mid] >= cur) r = mid;
else l = mid + 1;
}
vector<string> list;
if (products[r] >= cur) {
for (int j = r; j <= min(n - 1, r + 2); j++) {
if (products[j].length() < cur.length()) break;
if (products[j].substr(0, i + 1) != cur) break;
list.push_back(products[j]);
}
}
ans.push_back(list);
}
return ans;
}
};

1318. 或运算的最小翻转次数

问题地址:https://leetcode.cn/problems/minimum-flips-to-make-a-or-b-equal-to-c/

给你三个正整数 a、b 和 c。

你可以对 a 和 b 的二进制表示进行位翻转操作,返回能够使按位或运算   a OR b == c  成立的最小翻转次数。

「位翻转操作」是指将一个数的二进制表示任何单个位上的 1 变成 0 或者 0 变成 1 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int minFlips(int a, int b, int c) {
int ans = 0;
for (int i = 0; i < 31; ++i) {
int bit_a = (a >> i) & 1;
int bit_b = (b >> i) & 1;
int bit_c = (c >> i) & 1;
if (bit_c == 0) {
ans += bit_a + bit_b;
} else {
ans += (bit_a + bit_b == 0);
}
}
return ans;
}
};

2542. 最大子序列的分数

问题地址:https://leetcode.cn/problems/maximum-subsequence-score/

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,两者长度都是 n ,再给你一个正整数 k 。你必须从 nums1 中选一个长度为 k 的 子序列 对应的下标。

对于选择的下标 i0 ,i1 ,…, ik - 1 ,你的 分数 定义如下:

  • nums1 中下标对应元素求和,乘以 nums2 中下标对应元素的 最小值 。
  • 用公式表示: (nums1[i0] + nums1[i1] +…+ nums1[ik - 1]) * min(nums2[i0] , nums2[i1], … ,nums2[ik - 1]) 。

请你返回 最大 可能的分数。

一个数组的 子序列 下标是集合 {0, 1, …, n-1} 中删除若干元素得到的剩余集合,也可以不删除任何元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
long long maxScore(vector<int>& nums1, vector<int>& nums2, int k) {
long res = 0L;
int n = nums1.size();
vector<int> ids(n);
iota(ids.begin(), ids.end(), 0);
sort(ids.begin(), ids.end(), [&](int i, int j) {
return nums2[i] > nums2[j];
});
priority_queue<int, vector<int>, greater<int>> minHeap;
long sum1 = 0L;
for (int i = 0; i < k - 1; ++i) {
int id = ids[i];
sum1 += nums1[id];
minHeap.push(nums1[id]);
}
for (int i = k - 1; i < n; ++i) {
int id = ids[i];
int num1 = nums1[id];
sum1 += num1;
minHeap.push(num1);
res = max(sum1 * nums2[id], res);
sum1 -= minHeap.top();
minHeap.pop();
}
return res;
}
};

2462. 雇佣 K 位工人的总代价

问题地址:https://leetcode.cn/problems/total-cost-to-hire-k-workers/

给你一个下标从 0 开始的整数数组 costs ,其中 costs[i] 是雇佣第 i 位工人的代价。

同时给你两个整数 k 和 candidates 。我们想根据以下规则恰好雇佣 k 位工人:

  • 总共进行 k 轮雇佣,且每一轮恰好雇佣一位工人。
  • 在每一轮雇佣中,从最前面 candidates 和最后面 candidates 人中选出代价最小的一位工人,如果有多位代价相同且最小的工人,选择下标更小的一位工人。
    • 比方说,costs = [3,2,7,7,1,2] 且 candidates = 2 ,第一轮雇佣中,我们选择第 4 位工人,因为他的代价最小 [3,2,7,7,1,2] 。
    • 第二轮雇佣,我们选择第 1 位工人,因为他们的代价与第 4 位工人一样都是最小代价,而且下标更小,[3,2,7,7,2] 。注意每一轮雇佣后,剩余工人的下标可能会发生变化。
  • 如果剩余员工数目不足 candidates 人,那么下一轮雇佣他们中代价最小的一人,如果有多位代价相同且最小的工人,选择下标更小的一位工人。
  • 一位工人只能被选择一次。

返回雇佣恰好 k 位工人的总代价。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
long long totalCost(vector<int>& costs, int k, int candidates) {
priority_queue<int, vector<int>, greater<>> pq0, pq1;
int i = 0;
int j = costs.size() - 1;
long long ans = 0;
while (k--) {
while (pq0.size() < candidates && i <= j) {
pq0.push(costs[i++]);
}
while (pq1.size() < candidates && i <= j) {
pq1.push(costs[j--]);
}
int a = (pq0.size() > 0) ? pq0.top() : INT_MAX;
int b = (pq1.size() > 0) ? pq1.top() : INT_MAX;
if (a <= b) {
ans += a;
pq0.pop();
} else {
ans += b;
pq1.pop();
}
}
return ans;
}
};

2300. 咒语和药水的成功对数

问题地址:https://leetcode.cn/problems/successful-pairs-of-spells-and-potions/

给你两个正整数数组 spells 和 potions ,长度分别为 n 和 m ,其中 spells[i] 表示第 i 个咒语的能量强度,potions[j] 表示第 j 瓶药水的能量强度。

同时给你一个整数 success 。一个咒语和药水的能量强度 相乘 如果 大于等于 success ,那么它们视为一对 成功 的组合。

请你返回一个长度为 n 的整数数组 pairs,其中 pairs[i] 是能跟第 i 个咒语成功组合的 药水 数目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {
sort(potions.begin(), potions.end());
for (auto &x : spells) {
x = potions.end() - upper_bound(
potions.begin(),
potions.end(),
(success - 1) / x
);
}
return spells;
}
};

875. 爱吃香蕉的珂珂

问题地址:https://leetcode.cn/problems/koko-eating-bananas/

珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。

珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。

珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。

返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
int minEatingSpeed(vector<int>& piles, int h) {
int low = 1;
int high = 0;
for (int pile : piles) {
high = max(high, pile);
}
int k = high;
while (low < high) {
int speed = (high - low) / 2 + low;
long time = getTime(piles, speed);
if (time <= h) {
k = speed;
high = speed;
} else {
low = speed + 1;
}
}
return k;
}

long getTime(const vector<int>& piles, int speed) {
long time = 0;
for (int pile : piles) {
int curTime = (pile + speed - 1) / speed;
time += curTime;
}
return time;
}
};

216. 组合总和 III

问题地址:https://leetcode.cn/problems/combination-sum-iii/

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
private:
vector<int> temp;
vector<vector<int>> ans;
public:
vector<vector<int>> combinationSum3(int k, int n) {
dfs(1, 9, k, n);
return ans;
}
void dfs(int cur, int n, int k, int sum) {
if (temp.size() + (n - cur + 1) < k || temp.size() > k) {
return;
}
if (temp.size() == k && accumulate(temp.begin(), temp.end(), 0) == sum) {
ans.push_back(temp);
return;
}
temp.push_back(cur);
dfs(cur + 1, n, k, sum);
temp.pop_back();
dfs(cur + 1, n , k, sum);
}
};

1143. 最长公共子序列

问题地址:https://leetcode.cn/problems/longest-common-subsequence/

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m = text1.length(), n = text2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 1; i <= m; i++) {
char c1 = text1[i - 1];
for (int j = 1; j <= n; j++) {
char c2 = text2[j - 1];
if (c1 == c2) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
};

714. 买卖股票的最佳时机含手续费

问题地址:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/

给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n = prices.size();
vector<vector<int>> dp(n, vector<int>(2));
dp[0][0] = 0, dp[0][1] = -prices[0];
for (int i = 1; i < n; ++i) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[n - 1][0];
}
};

790. 多米诺和托米诺平铺

问题地址:https://leetcode.cn/problems/domino-and-tromino-tiling/

有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 “L” 的托米诺形。两种形状都可以旋转。

给定整数 n ,返回可以平铺 2 x n 的面板的方法的数量。返回对 109 + 7 取模 的值。

平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const long long mod = 1e9 + 7;
class Solution {
public:
int numTilings(int n) {
vector<vector<long long>> dp(n + 1, vector<long long>(4));
dp[0][3] = 1;
for (int i = 1; i <= n; i++) {
dp[i][0] = dp[i - 1][3];
dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % mod;
dp[i][2] = (dp[i - 1][0] + dp[i - 1][1]) % mod;
dp[i][3] = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3]) % mod;
}
return dp[n][3];
}
};

面试题 01.05. 一次编辑

问题地址:https://leetcode.cn/problems/one-away-lcci/

字符串有三种编辑操作:插入一个英文字符、删除一个英文字符或者替换一个英文字符。 给定两个字符串,编写一个函数判定它们是否只需要一次(或者零次)编辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
bool oneEditAway(string first, string second) {
int lf = first.length(), ls = second.length();
if (lf > ls) return oneEditAway(second, first);
if (ls - lf > 1) return false;
if (lf == ls) {
int count = 0;
for (int i = 0; i < lf; i++) {
if (first[i] != second[i]) count += 1;
}
return count <= 1;
}
int i = 0, ofs = 0;
while (i < lf) {
if (first[i] != second[i + ofs]) {
if (++ofs > 1) return false;
} else {
i += 1;
}
}
return true;
}
};

面试题 01.07. 旋转矩阵

问题地址:https://leetcode.cn/problems/rotate-matrix-lcci/

给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。

不占用额外内存空间能否做到?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < n; ++j) {
swap(matrix[i][j], matrix[n - i -1][j]);
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
swap(matrix[i][j], matrix[j][i]);
}
}
}
};

面试题 01.08. 零矩阵

问题地址:https://leetcode.cn/problems/zero-matrix-lcci/

编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<int> row(m), col(n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (!matrix[i][j]) {
row[i] = col[j] = true;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (row[i] || col[j]) {
matrix[i][j] = 0;
}
}
}
}
};

面试题 02.04. 分割链表

问题地址:https://leetcode.cn/problems/partition-list-lcci/

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你不需要 保留 每个分区中各节点的初始相对位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* small = new ListNode(0);
ListNode* smallHead = small;
ListNode* large = new ListNode(0);
ListNode* largeHead = large;
while (head != nullptr) {
if (head->val < x) {
small->next = head;
small = small->next;
} else {
large->next = head;
large = large->next;
}
head = head->next;
}
large->next = nullptr;
small->next = largeHead->next;
return smallHead->next;
}
};

面试题 02.05. 链表求和

问题地址:https://leetcode.cn/problems/sum-lists-lcci/

给定两个用链表表示的整数,每个节点包含一个数位。

这些数位是反向存放的,也就是个位排在链表首部。

编写函数对这两个整数求和,并用链表形式返回结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* head = nullptr, * tail = nullptr;
int carry = 0;
while (l1 || l2) {
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
int sum = n1 + n2 + carry;
if (!head) {
head = tail = new ListNode(sum % 10);
} else {
tail->next = new ListNode(sum % 10);
tail = tail->next;
}
carry = sum / 10;
if (l1) {
l1 = l1->next;
}
if (l2) {
l2 = l2->next;
}
}
if (carry > 0) {
tail->next = new ListNode(carry);
}
return head;
}
};

面试题 02.08. 环路检测

问题地址:https://leetcode.cn/problems/linked-list-cycle-lcci/

给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_set<ListNode*> visited;
while (head != nullptr) {
if (visited.count(head)) {
return head;
}
visited.insert(head);
head = head->next;
}
return nullptr;
}
};

面试题 03.03. 堆盘子

问题地址:https://leetcode.cn/problems/stack-of-plates-lcci/

堆盘子。设想有一堆盘子,堆太高可能会倒下来。因此,在现实生活中,盘子堆到一定高度时,我们就会另外堆一堆盘子。请实现数据结构SetOfStacks,模拟这种行为。SetOfStacks应该由多个栈组成,并且在前一个栈填满时新建一个栈。此外,SetOfStacks.push()和SetOfStacks.pop()应该与普通栈的操作方法相同(也就是说,pop()返回的值,应该跟只有一个栈时的情况一样)。 进阶:实现一个popAt(int index)方法,根据指定的子栈,执行pop操作。

当某个栈为空时,应当删除该栈。当栈中没有元素或不存在该栈时,pop,popAt 应返回 -1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class StackOfPlates {
private:
vector<stack<int>> stks;
int capacity;
public:
StackOfPlates(int cap) {
capacity = cap;
}

void push(int val) {
if (capacity == 0) {
return;
}
if (stks.empty() || stks.back().size() == capacity) {
stks.emplace_back(stack<int>());
}
stks.back().push(val);
}

int pop() {
if (capacity == 0 || stks.empty()) {
return -1;
}
int res = stks.back().top();
stks.back().pop();
if (stks.back().empty()) {
stks.pop_back();
}
return res;
}

int popAt(int index) {
if (capacity == 0 || index >= stks.size() || stks[index].empty()) {
return -1;
}
int res = stks[index].top();
stks[index].pop();
if (stks[index].empty()) {
stks.erase(stks.begin() + index);
}
return res;
}
};

/**
* Your StackOfPlates object will be instantiated and called as such:
* StackOfPlates* obj = new StackOfPlates(cap);
* obj->push(val);
* int param_2 = obj->pop();
* int param_3 = obj->popAt(index);
*/

面试题 03.05. 栈排序

问题地址:https://leetcode.cn/problems/sort-of-stacks-lcci/

栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push、pop、peek 和 isEmpty。当栈为空时,peek 返回 -1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class SortedStack {
private:
stack<int> st;
void mySort(int val) {
if (st.empty() || st.top() >= val) {
st.emplace(val);
} else {
int tmp = st.top();
st.pop();
mySort(val);
st.emplace(tmp);
}
}
public:
SortedStack() {}

void push(int val) {
mySort(val);
}

void pop() {
if (!st.empty()) st.pop();
}

int peek() {
if (st.empty()) return -1;
return st.top();
}

bool isEmpty() {
if (st.empty()) return true;
else return false;
}
};

/**
* Your SortedStack object will be instantiated and called as such:
* SortedStack* obj = new SortedStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->isEmpty();
*/

面试题 04.01. 节点间通路

问题地址:https://leetcode.cn/problems/route-between-nodes-lcci/

节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
private:
unordered_map<int, unordered_set<int>> m;
vector<bool> visited;
public:
bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
for (auto i = 0; i < graph.size(); i++) {
m[graph[i][0]].insert(graph[i][1]);
}
visited = vector<bool>(n, false);
return dfs(start, target);
}
bool dfs(int start, int target) {
if (start == target) {
return true;
}
if (visited[start]) {
return false;
}
visited[start] = true;
for (auto& neighbor : m[start]) {
if (dfs(neighbor, target)) {
return true;
}
}
return false;
}
};

面试题 04.03. 特定深度节点链表

问题地址:https://leetcode.cn/problems/list-of-depth-lcci/

给定一棵二叉树,设计一个算法,创建含有某一深度上所有节点的链表(比如,若一棵树的深度为 D,则会创建出 D 个链表)。返回一个包含所有深度的链表的数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<ListNode*> listOfDepth(TreeNode* tree) {
vector<ListNode*> res;
if (tree == nullptr) {
return res;
}
queue<TreeNode*> q;
q.push(tree);
while (!q.empty()) {
ListNode* head = nullptr;
ListNode* prev = nullptr;
int currSize = q.size();
for (int i = 0; i < currSize; ++i) {
TreeNode* currNode = q.front();
ListNode* newNode = new ListNode(currNode->val);
q.pop();
if (head == nullptr) {
head = newNode;
} else {
prev->next = newNode;
}
prev = newNode;
if (currNode->left != nullptr) {
q.push(currNode->left);
}
if (currNode->right != nullptr) {
q.push(currNode->right);
}
}
res.push_back(head);
}
return res;
}
};

面试题 04.05. 合法二叉搜索树

问题地址:https://leetcode.cn/problems/legal-binary-search-tree-lcci/

实现一个函数,检查一棵二叉树是否为二叉搜索树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
return helper(root, LONG_MIN, LONG_MAX);
}
bool helper(TreeNode* root, long long lower, long long upper) {
if (root == nullptr) {
return true;
}
if (root->val <= lower || root->val >= upper) {
return false;
}
return helper(root->left, lower, root->val) &&
helper(root->right, root->val, upper);
}
};

面试题 04.06. 后继者

问题地址:https://leetcode.cn/problems/successor-lcci/

设计一个算法,找出二叉搜索树中指定节点的“下一个”节点(也即中序后继)。

如果指定节点没有对应的“下一个”节点,则返回null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
stack<TreeNode*> st;
TreeNode* prev = nullptr, *curr = root;
while (!st.empty() || curr != nullptr) {
while (curr != nullptr) {
st.emplace(curr);
curr = curr->left;
}
curr = st.top();
st.pop();
if (prev == p) {
return curr;
}
prev = curr;
curr = curr->right;
}
return nullptr;
}
};

面试题 04.08. 首个共同祖先

问题地址:https://leetcode.cn/problems/first-common-ancestor-lcci/

设计并实现一个算法,找出二叉树中某两个节点的第一个共同祖先。不得将其他的节点存储在另外的数据结构中。注意:这不一定是二叉搜索树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
TreeNode* ans;
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) return false;
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root->val == p->val || root->val == q->val);
}
};

面试题 04.10. 检查子树

问题地址:https://leetcode.cn/problems/check-subtree-lcci/

检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。

如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。

注意:此题相对书上原题略有改动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool checkSubTree(TreeNode* t1, TreeNode* t2) {
if (t2 == nullptr) return true;
else if (t1 == nullptr) return false;
else {
return compare(t1, t2) || checkSubTree(t1->left, t2) || checkSubTree(t1->right, t2);
}

}
bool compare(TreeNode* t1, TreeNode* t2) {
if (t2 == nullptr && t1 != nullptr) return false;
if (t1 == nullptr && t2 != nullptr) return false;
if (t1 == nullptr && t2 == nullptr) return true;
if (t1->val == t2->val) {
return compare(t1->left, t2->left) && compare(t1->right, t2->right);
}
return false;
}
};

面试题 04.12. 求和路径

问题地址:https://leetcode.cn/problems/paths-with-sum-lcci/

给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int pathSum(TreeNode* root, int sum) {
if (!root) {
return 0;
}
int ret = rootSum(root, sum);
ret += pathSum(root->left, sum);
ret += pathSum(root->right, sum);
return ret;
}
int rootSum(TreeNode* root, int sum) {
if (!root) {
return 0;
}
int ret = 0;
if (root->val == sum) {
ret++;
}
ret += rootSum(root->left, sum - root->val);
ret += rootSum(root->right, sum - root->val);
return ret;
}
};

面试题 05.02. 二进制数转字符串

问题地址:https://leetcode.cn/problems/binary-number-to-string-lcci/

二进制数转字符串。给定一个介于0和1之间的实数(如0.72),类型为double,打印它的二进制表达式。如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
string printBin(double num) {
string res = "0.";
while (res.size() <= 32 && num != 0) {
num *= 2;
int digit = num;
res.push_back(digit + '0');
num -= digit;
}
return res.size() <= 32 ? res : "ERROR";
}
};

面试题 05.08. 绘制直线

问题地址:https://leetcode.cn/problems/draw-line-lcci/

已知一个由像素点组成的单色屏幕,每行均有 w 个像素点,所有像素点初始为 0,左上角位置为 (0,0)。

现将每行的像素点按照「每 32 个像素点」为一组存放在一个 int 中,再依次存入长度为 length 的一维数组中。

我们将在屏幕上绘制一条从点 (x1,y) 到点 (x2,y) 的直线(即像素点修改为 1),请返回绘制过后的数组。

注意:

  • 用例保证屏幕宽度 w 可被 32 整除(即一个 int 不会分布在两行上)
1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
vector<int> drawLine(int length, int w, int x1, int x2, int y) {
int per_row = w / 32;
vector<int> res(length, 0);
for (int i = x1; i <= x2 && i < length * 32; i++) {
res[y * per_row + i / 32] |= (1 << 31 - i % 32);
}
return res;
}
};

面试题 08.02. 迷路的机器人

问题地址:https://leetcode.cn/problems/robot-in-a-grid-lcci/

设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。

网格中的障碍物和空位置分别用 1 和 0 来表示。

返回一条可行的路径,路径由经过的网格的行号和列号组成。左上角为 0 行 0 列。如果没有可行的路径,返回空数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
vector<vector<int>> pathWithObstacles(vector<vector<int>>& obstacleGrid) {
vector<vector<int>> ans;
if (obstacleGrid.size() == 0 || obstacleGrid[0].size() == 0) return ans;
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
vector<vector<bool>> vis(m, vector<bool>(n, false));
function<bool(int, int)> dfs = [&](int x, int y) {
if (x >= m || y >= n || obstacleGrid[x][y] == 1 || vis[x][y]) return false;
if (x == m - 1 && y == n - 1) {
ans.push_back({x, y});
return true;
}
vis[x][y] = true;
ans.push_back({x, y});
if (dfs(x + 1, y) || dfs(x, y + 1)) {
return true;
}
ans.pop_back();
return false;
};
dfs(0, 0);
return ans;
}
};

面试题 08.04. 幂集

问题地址:https://leetcode.cn/problems/power-set-lcci/

幂集。编写一种方法,返回某集合的所有子集。集合中不包含重复的元素。

说明:解集不能包含重复的子集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
vector<int> t;
vector<vector<int>> ans;
for (int mask = 0; mask < (1 << n); ++mask) {
t.clear();
for (int i = 0; i < n; ++i) {
if (mask & (1 << i)) {
t.push_back(nums[i]);
}
}
ans.push_back(t);
}
return ans;
}
};

面试题 08.05. 递归乘法

问题地址:https://leetcode.cn/problems/recursive-mulitply-lcci/

递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。

1
2
3
4
5
6
7
8
class Solution {
public:
int multiply(int A, int B) {
if (B == 1) return A;
return (B & 1) ? (multiply(A, B >> 1) << 1) + A :
multiply(A, B >> 1) << 1;
}
};

面试题 08.07. 无重复字符串的排列组合

问题地址:https://leetcode.cn/problems/permutation-i-lcci/

无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
vector<string> permutation(string S) {
vector<string> res;
dfs(res, S, 0);
return res;
}
void dfs(vector<string>& res, string& S, int i) {
if (i == S.length()) {
res.push_back(S);
} else {
for (int j = i; j < S.length(); ++j) {
swap(S[i], S[j]);
dfs(res, S, i + 1);
swap(S[i], S[j]);
}
}
}
};

面试题 08.08. 有重复字符串的排列组合

问题地址:https://leetcode.cn/problems/permutation-ii-lcci/

有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
vector<string> permutation(string S) {
vector<string> res;
dfs(res, S, 0);
return res;
}
void dfs(vector<string>& res, string& S, int i) {
if (i == S.length()) {
res.push_back(S);
return;
}
set<char> hash;
for (int j = i; j < S.length(); ++j) {
if (hash.find(S[j]) == hash.end()) {
hash.insert(S[j]);
swap(S[i], S[j]);
dfs(res, S, i + 1);
swap(S[i], S[j]);
}
}
}
};

面试题 08.09. 括号

问题地址:https://leetcode.cn/problems/bracket-lcci/

括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。

说明:解集不能包含重复的子集。

例如,给出 n = 3,生成结果为:

1
2
3
4
5
6
7
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> result;
string current;
backtrack(result, current, 0, 0, n);
return result;
}
void backtrack(vector<string>& ans, string& cur, int open, int close, int n) {
if (cur.size() == n * 2) {
ans.push_back(cur);
return;
}
if (open < n) {
cur.push_back('(');
backtrack(ans, cur, open + 1, close, n);
cur.pop_back();
}
if (close < open) {
cur.push_back(')');
backtrack(ans, cur, open, close + 1, n);
cur.pop_back();
}
}
};

面试题 08.11. 硬币

问题地址:https://leetcode.cn/problems/coin-lcci/

硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
private:
static constexpr int mod = 1000000007;
static constexpr int coins[4] = {25, 10, 5, 1};
public:
int waysToChange(int n) {
vector<int> f(n + 1);
f[0] = 1;
for (int c = 0; c < 4; ++c) {
int coin = coins[c];
for (int i = coin; i <= n; ++i) {
f[i] = (f[i] + f[i - coin]) % mod;
}
}
return f[n];
}
};

面试题 08.14. 布尔运算

问题地址:https://leetcode.cn/problems/boolean-evaluation-lcci/

给定一个布尔表达式和一个期望的布尔结果 result,布尔表达式由 0 (false)、1 (true)、& (AND)、 | (OR) 和 ^ (XOR) 符号组成。实现一个函数,算出有几种可使该表达式得出 result 值的括号方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Solution {
public:

int countEval(string s, int result) {
int size = s.size();

vector<int> digits;
vector<char> ops;
for(int i = 1; i < size; i+=2){
digits.push_back(s[i-1] - '0' );
ops.push_back(s[i]);
}
digits.push_back(s.back() - '0');

vector<vector<vector<int>>> dp(digits.size(), vector<vector<int> >(digits.size(), vector<int>(2, 0) ) );

for(int i = digits.size() - 1; i >= 0; i--){
for(int j = i; j < digits.size(); j++ ){
if(i == j){
dp[i][j][0] = digits[i] == 0;
dp[i][j][1] = digits[i] == 1;
continue;
}
for(int k = i; k < j; k++){
char op = ops[k];

for(int left = 0; left < 2; left++ ){
for(int rght = 0; rght < 2; rght++ ){
if (getBoolAns(left, rght, op) == 0 ) {
dp[i][j][0] += dp[i][k][left] * dp[k+1][j][rght];
} else{
dp[i][j][1] += dp[i][k][left] * dp[k+1][j][rght];
}
}
}
}
}
}
return dp[0][digits.size() - 1][result];
}

int getBoolAns(int val1, int val2, char op) {
switch(op){
case '&':
return val1 & val2;
case '|':
return val1 | val2;
case '^':
return val1 ^ val2;

}
return 1;
}
};

面试题 10.02. 变位词组

问题地址:https://leetcode.cn/problems/group-anagrams-lcci/

编写一种方法,对字符串数组进行排序,将所有变位词组合在一起。变位词是指字母相同,但排列不同的字符串。

注意:本题相对原题稍作修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
for (string& str : strs) {
string key = str;
sort(key.begin(), key.end());
mp[key].emplace_back(str);
}
vector<vector<string>> ans;
for (auto it = mp.begin(); it != mp.end(); ++it) {
ans.emplace_back(it->second);
}
return ans;
}
};

面试题 10.03. 搜索旋转数组

问题地址:https://leetcode.cn/problems/search-rotate-array-lcci/

搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
int search(vector<int>& arr, int target) {
int left = 0;
int right = arr.size() - 1;
if (right == -1) return -1;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[left] < arr[mid]) {
if (arr[left] <= target && target <= arr[mid]) {
right = mid;
} else {
left = mid + 1;
}
} else if (arr[left] > arr[mid]) {
if (arr[left] <= target || target <= arr[mid]) {
right = mid;
} else {
left = mid + 1;
}
} else if (arr[left] == arr[mid]) {
if (arr[left] != target) {
left++;
} else {
right = left;
}
}
}
return (arr[left] == target) ? left : -1;
}
};

面试题 10.09. 排序矩阵查找

问题地址:https://leetcode.cn/problems/sorted-matrix-search-lcci/

给定M×N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if (matrix.size() == 0 || matrix[0].size() == 0) {
return false;
}
for (const auto& row : matrix) {
for (auto element : row) {
if (element == target) {
return true;
}
}
}
return false;
}
};

面试题 10.10. 数字流的秩

问题地址:https://leetcode.cn/problems/rank-from-stream-lcci/

假设你正在读取一串整数。每隔一段时间,你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。请实现数据结构和算法来支持这些操作,也就是说:

实现 track(int x) 方法,每读入一个数字都会调用该方法;

实现 getRankOfNumber(int x) 方法,返回小于或等于 x 的值的个数。

注意:本题相对原题稍作改动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class StreamRank {
private:
vector<int> v;
public:
StreamRank() {}

void track(int x) {
auto it = upper_bound(v.begin(), v.end(), x);
v.insert(it, x);
}

int getRankOfNumber(int x) {
return upper_bound(v.begin(), v.end(), x) - v.begin();
}
};

/**
* Your StreamRank object will be instantiated and called as such:
* StreamRank* obj = new StreamRank();
* obj->track(x);
* int param_2 = obj->getRankOfNumber(x);
*/

面试题 10.11. 峰与谷

问题地址:https://leetcode.cn/problems/peaks-and-valleys-lcci/

在一个整数数组中,“峰”是大于或等于相邻整数的元素,相应地,“谷”是小于或等于相邻整数的元素。例如,在数组{5, 8, 4, 2, 3, 4, 6}中,{8, 6}是峰, {5, 2}是谷。现在给定一个整数数组,将该数组按峰与谷的交替顺序排序。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
void wiggleSort(vector<int>& nums) {
for (int i = 1; i < nums.size(); i++) {
if (i % 2 == 0) {
if (nums[i] < nums[i - 1]) swap(nums[i], nums[i - 1]);
} else {
if (nums[i] > nums[i - 1]) swap(nums[i], nums[i - 1]);
}
}
}
};

面试题 16.01. 交换数字

问题地址:https://leetcode.cn/problems/swap-numbers-lcci/

编写一个函数,不用临时变量,直接交换numbers = [a, b]中a与b的值。

1
2
3
4
5
6
7
8
9
class Solution {
public:
vector<int> swapNumbers(vector<int>& numbers) {
numbers[0] ^= numbers[1];
numbers[1] ^= numbers[0];
numbers[0] ^= numbers[1];
return numbers;
}
};

面试题 16.02. 单词频率

问题地址:https://leetcode.cn/problems/words-frequency-lcci/

设计一个方法,找出任意指定单词在一本书中的出现频率。

你的实现应该支持如下操作:

  • WordsFrequency(book)构造函数,参数为字符串数组构成的一本书
  • get(word)查询指定单词在书中出现的频率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class WordsFrequency {
private:
unordered_map<string, int> map;
public:
WordsFrequency(vector<string>& book) {
for (auto word : book) map[word]++;
}

int get(string word) {
return map[word];
}
};

/**
* Your WordsFrequency object will be instantiated and called as such:
* WordsFrequency* obj = new WordsFrequency(book);
* int param_1 = obj->get(word);
*/

面试题 16.04. 井字游戏

问题地址:https://leetcode.cn/problems/tic-tac-toe-lcci/

设计一个算法,判断玩家是否赢了井字游戏。输入是一个 N x N 的数组棋盘,由字符" ",“X"和"O"组成,其中字符” "代表一个空位。

以下是井字游戏的规则:

  • 玩家轮流将字符放入空位(" ")中。
  • 第一个玩家总是放字符"O",且第二个玩家总是放字符"X"。
  • "X"和"O"只允许放置在空位中,不允许对已放有字符的位置进行填充。
  • 当有N个相同(且非空)的字符填充任何行、列或对角线时,游戏结束,对应该字符的玩家获胜。
  • 当所有位置非空时,也算为游戏结束。
  • 如果游戏结束,玩家不允许再放置字符。

如果游戏存在获胜者,就返回该游戏的获胜者使用的字符(“X"或"O”);如果游戏以平局结束,则返回 “Draw”;如果仍会有行动(游戏未结束),则返回 “Pending”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
string tictactoe(vector<string>& board) {
auto n = board.size();
int row_sum = 0, col_sum = 0, left_dia_sum = 0, right_dia_sum = 0, isFull = 1;
for (auto i = 0; i < n; i++) {
row_sum = 0, col_sum = 0;
left_dia_sum += board[i][i];
right_dia_sum += board[i][n - 1 - i];
for (auto j = 0; j < n; j++) {
row_sum += board[i][j];
col_sum += board[j][i];
if (board[i][j] == ' ') isFull = 0;
}
if (row_sum == ((int)'X') * n || col_sum == ((int)'X') * n) {
return string("X");
}
if (row_sum == ((int)'O') * n || col_sum == ((int)'O') * n) {
return string("O");
}
}
if (left_dia_sum == ((int)'X') * n || right_dia_sum == ((int)'X') * n) {
return string("X");
}
if (left_dia_sum == ((int)'O') * n || right_dia_sum == ((int)'O') * n) {
return string("O");
}
if (isFull) {
return string("Draw");
} else {
return string("Pending");
}
}
};

面试题 16.06. 最小差

问题地址:https://leetcode.cn/problems/smallest-difference-lcci/

给定两个整数数组a和b,计算具有最小差绝对值的一对数值(每个数组中取一个值),并返回该对数值的差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int smallestDifference(vector<int>& a, vector<int>& b) {
sort(a.begin(), a.end());
sort(b.begin(), b.end());
int na = a.size();
int i = 0;
int nb = b.size();
int j = 0;
long res = LONG_MAX;
while (i < na && j < nb) {
if (a[i] != b[j]) {
res = min(res, abs((long)a[i] - (long)b[j]));
a[i] > b[j] ? ++j : ++i;
} else {
return 0;
}
}
return res;
}
};

面试题 16.09. 运算

问题地址:https://leetcode.cn/problems/operations-lcci/

请实现整数数字的乘法、减法和除法运算,运算结果均为整数数字,程序中只允许使用加法运算符和逻辑运算符,允许程序中出现正负常数,不允许使用位运算。

你的实现应该支持如下操作:

  • Operations() 构造函数
  • minus(a, b) 减法,返回a - b
  • multiply(a, b) 乘法,返回a * b
  • divide(a, b) 除法,返回a / b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class Operations {
private:
vector<int> negs, poss;

int neg(int a) {
if (!a) return 0;
int result = 0;
if (a > 0) {
for (auto p = negs.rbegin(); p != negs.rend(); p++) {
if (*p + a < 0) continue;
a += *p;
result += *p;
}
} else {
for (auto p = poss.rbegin(); p != poss.rend(); p++) {
if (*p + a > 0) continue;
a += *p;
result += *p;
}
}
return result;
}
public:
Operations() {
int p = 1, n = -1;
poss.push_back(p);
negs.push_back(n);

for (auto i = 0; i < 30; i++) {
p += p;
n += n;

poss.push_back(p);
negs.push_back(n);
}
}

int minus(int a, int b) {
return a + neg(b);
}

int multiply(int a, int b) {
if (!a || !b) return 0;
if (a == 1) return b;
if (b < 0) return neg(multiply(a, neg(b)));

int result = a;
int times = 1;

while (times < poss[30] && times + times <= b) {
result += result;
times += times;
}
result += multiply(a, minus(b, times));
return result;
}

int divide(int a, int b) {
if (!a) return 0;
int result = 1;
if (a > 0) {
if (b == INT_MIN) return 0;
if (b < 0) return neg(divide(a, neg(b)));
if (a < b) return 0;

int acc = b;
while (acc < poss[30] && a >= acc + acc) {
result += result;
acc += acc;
}
result += divide(minus(a, acc), b);
} else {
if (b == 1) return a;
if (b > 0) return neg(divide(a, neg(b)));
if (a > b) return 0;

int acc = b;
while (acc >= negs[30] && a <= acc + acc) {
result += result;
acc += acc;
}
result += divide(minus(a, acc), b);
}
return result;
}
};

/**
* Your Operations object will be instantiated and called as such:
* Operations* obj = new Operations();
* int param_1 = obj->minus(a,b);
* int param_2 = obj->multiply(a,b);
* int param_3 = obj->divide(a,b);
*/

面试题 16.10. 生存人数

问题地址:https://leetcode.cn/problems/living-people-lcci/

给定 N 个人的出生年份和死亡年份,第 i 个人的出生年份为 birth[i],死亡年份为 death[i],实现一个方法以计算生存人数最多的年份。

你可以假设所有人都出生于 1900 年至 2000 年(含 1900 和 2000 )之间。如果一个人在某一年的任意时期处于生存状态,那么他应该被纳入那一年的统计中。例如,生于 1908 年、死于 1909 年的人应当被列入 1908 年和 1909 年的计数。

如果有多个年份生存人数相同且均为最大值,输出其中最小的年份。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int maxAliveYear(vector<int>& birth, vector<int>& death) {
int n = birth.size();
vector<int> a(2002, 0);
for (auto i = 0; i < n; i++) {
int x = birth[i], y = death[i];
a[x] += 1; a[y+1] -= 1;
}
int mx = 0, year = 0, sum(0);
for (auto i = 1900; i <= 2000; ++i) {
sum += a[i];
if (mx < sum) {
mx = sum;
year = i;
}
}
return year;
}
};

面试题 16.21. 交换和

问题地址:https://leetcode.cn/problems/sum-swap-lcci/

给定两个整数数组,请交换一对数值(每个数组中取一个数值),使得两个数组所有元素的和相等。

返回一个数组,第一个元素是第一个数组中要交换的元素,第二个元素是第二个数组中要交换的元素。若有多个答案,返回任意一个均可。若无满足条件的数值,返回空数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
vector<int> findSwapValues(vector<int>& array1, vector<int>& array2) {
int sum1 = 0, sum2 = 0;
for (auto num : array1) sum1 += num;
for (auto num : array2) sum2 += num;
if ((sum1 - sum2) % 2) return {};
unordered_set<int> set(array2.begin(), array2.end());
const int diff = (sum1 - sum2) / 2;
for (auto x : array1) {
auto y = x - diff;
if (set.count(y)) return {x, y};
}
return {};
}
};

面试题 16.24. 数对和

问题地址:https://leetcode.cn/problems/pairs-with-sum-lcci/

设计一个算法,找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
vector<vector<int>> pairSums(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int l = 0;
int r = nums.size() - 1;
vector<vector<int>> ret;
while (l < r) {
if (nums[l] + nums[r] == target) {
ret.push_back({nums[l], nums[r]});
l++;
r--;
} else if (nums[l] + nums[r] > target) {
r--;
} else {
l++;
}
}
return ret;
}
};

40. 组合总和 II

问题地址:https://leetcode.cn/problems/combination-sum-ii/

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
private:
vector<int> candidates;
vector<vector<int>> res;
vector<int> path;
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
this->candidates = candidates;
dfs(0, target);
return res;
}
void dfs(int start, int target) {
if (target == 0) {
res.push_back(path);
return;
}
for (auto i = start; i < candidates.size() && target - candidates[i] >= 0; i++) {
if (i > start && candidates[i] == candidates[i - 1]) continue;
path.push_back(candidates[i]);
dfs(i + 1, target - candidates[i]);
path.pop_back();
}
}
};

47. 全排列 II

问题地址:https://leetcode.cn/problems/permutations-ii/

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
private:
vector<int> vis;
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> ans;
vector<int> perm;
vis.resize(nums.size());
sort(nums.begin(), nums.end());
backtrack(nums, ans, 0, perm);
return ans;
}
void backtrack(vector<int>& nums, vector<vector<int>>& ans, int idx, vector<int>& perm) {
if (idx == nums.size()) {
ans.emplace_back(perm);
return;
}
for (int i = 0; i < (int)nums.size(); ++i) {
if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) {
continue;
}
perm.emplace_back(nums[i]);
vis[i] = 1;
backtrack(nums, ans, idx + 1, perm);
vis[i] = 0;
perm.pop_back();
}
}
};

75. 颜色分类

问题地址:https://leetcode.cn/problems/sort-colors/

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size();
int ptr = 0;
for (auto i = 0; i < n; ++i) {
if (nums[i] == 0) {
swap(nums[i], nums[ptr]);
++ptr;
}
}
for (auto i = ptr; i < n; ++i) {
if (nums[i] == 1) {
swap(nums[i], nums[ptr]);
++ptr;
}
}
}
};

90. 子集 II

问题地址:https://leetcode.cn/problems/subsets-ii/

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> res;
vector<int> tmp;

function<void(int)> dfs = [&](int idx) {
res.push_back(tmp);
for (int i = idx; i < n; ++i) {
if (i - 1 >= idx && nums[i - 1] == nums[i]) continue;
tmp.push_back(nums[i]);
dfs(i + 1);
tmp.pop_back();
}
};
dfs(0);
return res;
}
};

LCR 121. 寻找目标值 - 二维数组

问题地址:https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/

m*n 的二维数组 plants 记录了园林景观的植物排布情况,具有以下特性:

  • 每行中,每棵植物的右侧相邻植物不矮于该植物;
  • 每列中,每棵植物的下侧相邻植物不矮于该植物。

请判断 plants 中是否存在目标高度值 target。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
bool findTargetIn2DPlants(vector<vector<int>>& plants, int target) {
int i = plants.size() - 1, j = 0;
while (i >= 0 && j < plants[0].size()) {
if (plants[i][j] > target) i--;
else if (plants[i][j] < target) j++;
else return true;
}
return false;
}
};

347. 前 K 个高频元素

问题地址:https://leetcode.cn/problems/top-k-frequent-elements/

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
private:
static bool cmp(pair<int, int>& m, pair<int, int>& n) {
return m.second > n.second;
}
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> occurrences;
for (auto& v : nums) {
occurrences[v]++;
}

priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp);
for (auto& [num, count] : occurrences) {
if (q.size() == k) {
if (q.top().second < count) {
q.pop();
q.emplace(num, count);
}
} else {
q.emplace(num, count);
}
}
vector<int> ret;
while (!q.empty()) {
ret.emplace_back(q.top().first);
q.pop();
}
return ret;
}
};

438. 找到字符串中所有字母异位词

问题地址:https://leetcode.cn/problems/find-all-anagrams-in-a-string/

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int sLen = s.size(), pLen = p.size();

if (sLen < pLen) {
return vector<int>();
}

vector<int> ans;
vector<int> sCount(26);
vector<int> pCount(26);
for (auto i = 0; i < pLen; ++i) {
++sCount[s[i] - 'a'];
++pCount[p[i] - 'a'];
}

if (sCount == pCount) {
ans.emplace_back(0);
}

for (int i = 0; i < sLen - pLen; ++i) {
--sCount[s[i] - 'a'];
++sCount[s[i + pLen] - 'a'];

if (sCount == pCount) {
ans.emplace_back(i + 1);
}
}

return ans;
}
};

560. 和为 K 的子数组

问题地址:https://leetcode.cn/problems/subarray-sum-equals-k/

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

子数组是数组中元素的连续非空序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> mp;
mp[0] = 1;
int count = 0, pre = 0;
for (auto& x : nums) {
pre += x;
if (mp.find(pre - k) != mp.end()) {
count += mp[pre - k];
}
mp[pre]++;
}
return count++;
}
};

240. 搜索二维矩阵 II

问题地址:https://leetcode.cn/problems/search-a-2d-matrix-ii/

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int r = matrix.size(), c = matrix[0].size();
int i = 0, j = c - 1;
while (i < r && j > -1) {
if (matrix[i][j] == target) {
return true;
}
if (matrix[i][j] > target) {
--j;
}
else {
++i;
}
}
return false;
}
};

131. 分割回文串

问题地址:https://leetcode.cn/problems/palindrome-partitioning/

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
private:
vector<vector<int>> f;
vector<vector<string>> ret;
vector<string> ans;
int n;

public:
void dfs(const string& s, int i) {
if (i == n) {
ret.push_back(ans);
return;
}
for (int j = i; j < n; ++j) {
if (f[i][j]) {
ans.push_back(s.substr(i, j - i + 1));
dfs(s, j + 1);
ans.pop_back();
}
}
}

vector<vector<string>> partition(string s) {
n = s.size();
f.assign(n, vector<int>(n, true));

for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
f[i][j] = (s[i] == s[j]) && f[i + 1][j - 1];
}
}

dfs(s, 0);
return ret;
}
};

763. 划分字母区间

问题地址:https://leetcode.cn/problems/partition-labels/

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
vector<int> partitionLabels(string s) {
int last[26];
int length = s.size();
for (int i = 0; i < length; i++) {
last[s[i] - 'a'] = i;
}
vector<int> partition;
int start = 0, end = 0;
for (int i = 0; i < length; i++) {
end = max(end, last[s[i] - 'a']);
if (i == end) {
partition.push_back(end - start + 1);
start = end + 1;
}
}
return partition;
}
};

279. 完全平方数

问题地址:https://leetcode.cn/problems/perfect-squares/

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int numSquares(int n) {
vector<int> f(n + 1);
for (int i = 1; i <= n; i++) {
int minn = INT_MAX;
for (int j = 1; j * j <= i; j++) {
minn = min(minn, f[i - j * j]);
}
f[i] = minn + 1;
}
return f[n];
}
};

287. 寻找重复数

问题地址:https://leetcode.cn/problems/find-the-duplicate-number/

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int findDuplicate(vector<int>& nums) {
unordered_map<int, bool> map;
for (auto num : nums) {
if (map[num]) return num;
map[num] = true;
}
return -1;
}
};

152. 乘积最大子数组

问题地址:https://leetcode.cn/problems/maximum-product-subarray/

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

子数组 是数组的连续子序列。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int maxProduct(vector<int>& nums) {
vector<int> maxF(nums), minF(nums);
for (int i = 1; i < nums.size(); ++i) {
maxF[i] = max(maxF[i - 1] * nums[i], max(nums[i], minF[i - 1] * nums[i]));
minF[i] = min(minF[i - 1] * nums[i], min(nums[i], maxF[i - 1] * nums[i]));
}
return *max_element(maxF.begin(), maxF.end());
}
};

416. 分割等和子集

问题地址:https://leetcode.cn/problems/partition-equal-subset-sum/

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size(), m = 0;
for (auto x : nums) m += x;
if (m % 2) return false;
m /= 2;
vector<bool> f(m + 1);
f[0] = true;
for (auto i = 1; i <= n; i++) {
for (auto j = m; j >= nums[i - 1]; j--) {
f[j] = f[j] || f[j - nums[i - 1]];
}
}
return f[m];
}
};

困难

220. 存在重复元素 III

问题地址:https://leetcode.cn/problems/contains-duplicate-iii/

给你一个整数数组 nums 和两个整数 indexDiffvalueDiff

找出满足下述条件的下标对 (i, j)

  • i != j,
  • abs(i - j) <= indexDiff
  • abs(nums[i] - nums[j]) <= valueDiff

如果存在,返回 true ;否则,返回 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
int getID(int x, long w) {
return x < 0 ? (x + 1ll) / w - 1 : x / w;
}

bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
unordered_map<int, int> mp;
int n = nums.size();
for (int i = 0; i < n; i++) {
long x = nums[i];
int id = getID(x, t + 1ll);
if (mp.count(id)) {
return true;
}
if (mp.count(id - 1) && abs(x - mp[id - 1]) <= t) {
return true;
}
if (mp.count(id + 1) && abs(x - mp[id + 1]) <= t) {
return true;
}
mp[id] = x;
if (i >= k) {
mp.erase(getID(nums[i - k], t + 1ll));
}
}
return false;
}
};

140. 单词拆分 II

问题地址:https://leetcode.cn/problems/word-break-ii/

给定一个字符串 s 和一个字符串字典 wordDict ,在字符串 s 中增加空格来构建一个句子,使得句子中所有的单词都在词典中。以任意顺序 返回所有这些可能的句子。

注意:词典中的同一个单词可能在分段中被重复使用多次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
private:
unordered_map<int, vector<string>> ans;
unordered_set<string> wordSet;
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
wordSet = unordered_set(wordDict.begin(), wordDict.end());
backtrack(s, 0);
return ans[0];
}

void backtrack(const string& s, int index) {
if (!ans.count(index)) {
if (index == s.size()) {
ans[index] = {""};
return;
}
ans[index] = {};
for (int i = index + 1; i <= s.size(); ++i) {
string word = s.substr(index, i - index);
if (wordSet.count(word)) {
backtrack(s, i);
for (const string& succ : ans[i]) {
ans[index].push_back(succ.empty() ? word : word + " " + succ);
}
}
}
}
}
};

732. 我的日程安排表 III

问题地址:https://leetcode.cn/problems/my-calendar-iii/

k 个日程安排有一些时间上的交叉时(例如 k 个日程安排都在同一时间内),就会产生 k 次预订。

给你一些日程安排 [start, end) ,请你在每个日程安排添加后,返回一个整数 k ,表示所有先前日程安排会产生的最大 k 次预订。

实现一个 MyCalendarThree 类来存放你的日程安排,你可以一直添加新的日程安排。

  • MyCalendarThree() 初始化对象。
  • int book(int start, int end) 返回一个整数 k ,表示日历中存在的 k 次预订的最大值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyCalendarThree {
public:
MyCalendarThree() {

}

int book(int start, int end) {
int ans = 0;
int maxBook = 0;
cnt[start]++;
cnt[end]--;
for (auto &[_, freq] : cnt) {
maxBook += freq;
ans = max(maxBook, ans);
}
return ans;
}
private:
map<int, int> cnt;
};

768. 最多能完成排序的块 II

问题地址:https://leetcode.cn/problems/max-chunks-to-make-sorted-ii/

给你一个整数数组 arr 。

将 arr 分割成若干 块 ,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。

返回能将数组分成的最多块数?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
unordered_map<int, int> cnt;
int res = 0;
vector<int> sortedArr = arr;
sort(sortedArr.begin(), sortedArr.end());
for (int i = 0; i < sortedArr.size(); i++) {
int x = arr[i], y = sortedArr[i];
cnt[x]++;
if (cnt[x] == 0) {
cnt.erase(x);
}
cnt[y]--;
if (cnt[y] == 0) {
cnt.erase(y);
}
if (cnt.size() == 0) {
res++;
}
}
return res;
}
};

4. 寻找两个正序数组的中位数

问题地址:https://leetcode.cn/problems/median-of-two-sorted-arrays/

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size(), n = nums2.size(), i = 0, j = 0, l = 0, r = 0;
for (int x = 0; x <= (m + n) / 2; x++) {
l = r;
r = (i < m && (j >= n || nums1[i] < nums2[j])) ?
nums1[i++] : nums2[j++];
}
return (m + n) & 1 ? r : (l + r) / 2.0;
}
};

10. 正则表达式匹配

问题地址:https://leetcode.cn/problems/regular-expression-matching/

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

  • ‘.’ 匹配任意单个字符
  • ‘*’ 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size();
int n = p.size();
auto matches = [&](int i, int j) {
if (i == 0) {
return false;
}
if (p[j - 1] == '.') {
return true;
}
return s[i - 1] == p[j - 1];
};

vector<vector<int>> f(m + 1, vector<int>(n + 1));
f[0][0] = true;
for (int i = 0; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '*') {
f[i][j] |= f[i][j - 2];
if (matches(i, j - 1)) {
f[i][j] |= f[i - 1][j];
}
}
else {
if (matches(i, j)) {
f[i][j] |= f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
};

23. 合并 K 个升序链表

问题地址:https://leetcode.cn/problems/merge-k-sorted-lists/

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode * ans = nullptr;
for (size_t i = 0; i < lists.size(); ++i) {
ans = mergeTwoLists(ans, lists[i]);
}
return ans;
}

ListNode * mergeTwoLists(ListNode * a, ListNode * b) {
if ((!a) || (!b)) return a ? a : b;
ListNode head, * tail = &head, * aPtr = a, * bPtr = b;
while (aPtr && bPtr) {
if (aPtr->val < bPtr->val) {
tail->next = aPtr; aPtr = aPtr->next;
} else {
tail->next = bPtr; bPtr = bPtr->next;
}
tail = tail->next;
}
tail->next = (aPtr ? aPtr : bPtr);
return head.next;
}
};

25. K 个一组翻转链表

问题地址:https://leetcode.cn/problems/reverse-nodes-in-k-group/

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
stack<ListNode *> stk;
ListNode * res = new ListNode(0);
ListNode * p = res, * q;
int i;
while (head) {
for (i = 0; head && i < k; i++) {
stk.push(head);
head = head->next;
}
if (i != k) break;
while (!stk.empty()) {
p->next = stk.top();
p = p->next;
stk.pop();
}
q = head;
}
p->next = q;
return res->next;
}
};

2763. 所有子数组中不平衡数字之和

问题地址:https://leetcode.cn/problems/sum-of-imbalance-numbers-of-all-subarrays/

一个长度为 n 下标从 0 开始的整数数组 arr 的 不平衡数字 定义为,在 sarr = sorted(arr) 数组中,满足以下条件的下标数目:

  • 0 <= i < n - 1 ,和
  • sarr[i+1] - sarr[i] > 1

这里,sorted(arr) 表示将数组 arr 排序后得到的数组。

给你一个下标从 0 开始的整数数组 nums ,请你返回它所有 子数组 的 不平衡数字 之和。

子数组指的是一个数组中连续一段 非空 的元素序列。

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= nums.length
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int sumImbalanceNumbers(vector<int>& nums) {
int ans = 0, n = nums.size();
bool vis[n + 2];
for (int i = 0; i < n; i++) {
memset(vis, 0, sizeof(vis));
vis[nums[i]] = true;
int cnt = 0;
for (int j = i + 1; j < n; j++) {
int x = nums[j];
if (!vis[x]) {
cnt += 1 - vis[x - 1] - vis[x + 1];
vis[x] = true;
}
ans += cnt;
}
}
return ans;
}
};

30. 串联所有单词的子串

问题地址:https://leetcode.cn/problems/substring-with-concatenation-of-all-words/

给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。

s 中的 串联子串 是指一个包含  words 中所有字符串以任意顺序排列连接起来的子串。

  • 例如,如果 words = ["ab","cd","ef"], 那么 “abcdef”, “abefcd”,“cdabef”, “cdefab”,“efabcd”, 和 “efcdab” 都是串联子串。 “acdbef” 不是串联子串,因为他不是任何 words 排列的连接。

返回所有串联子串在 s 中的开始索引。你可以以 任意顺序 返回答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> res;
int m = words.size(), n = words[0].size(), ls = s.size();
for (int i = 0; i < n && i + m * n <= ls; ++i) {
unordered_map<string, int> differ;
for (int j = 0; j < m; ++j) {
++differ[s.substr(i + j * n, n)];
}
for (string &word : words) {
if (--differ[word] == 0) {
differ.erase(word);
}
}
for (int start = i; start < ls - m * n + 1; start += n) {
if (start != i) {
string word = s.substr(start + (m - 1) * n, n);
if (++differ[word] == 0) {
differ.erase(word);
}
word = s.substr(start - n, n);
if (--differ[word] == 0) {
differ.erase(word);
}
}
if (differ.empty()) {
res.emplace_back(start);
}
}
}
return res;
}
};

32. 最长有效括号

问题地址:https://leetcode.cn/problems/longest-valid-parentheses/

给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int longestValidParentheses(string s) {
int maxans = 0, n = s.length();
vector<int> dp(n, 0);
for (int i = 1; i < n; i++) {
if (s[i] == ')') {
if (s[i - 1] == '(') {
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
} else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] == '(') {
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
maxans = max(maxans, dp[i]);
}
}
return maxans;
}
};

37. 解数独

问题地址:https://leetcode.cn/problems/sudoku-solver/

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
private:
bool line[9][9];
bool column[9][9];
bool block[3][3][9];
bool valid;
vector<pair<int, int>> spaces;
public:
void dfs(vector<vector<char>>& board, int pos) {
if (pos == spaces.size()) {
valid = true;
return;
}

auto [i, j] = spaces[pos];
for (int digit = 0; digit < 9 && !valid; ++digit) {
if (!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) {
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;
board[i][j] = digit + '0' + 1;
dfs(board, pos + 1);
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false;
}
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(line, false, sizeof(line));
memset(column, false, sizeof(column));
memset(block, false, sizeof(block));
valid = false;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] == '.') {
spaces.emplace_back(i, j);
} else {
int digit = board[i][j] - '0' - 1;
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;
}
}
}
dfs(board, 0);
}
};

C++ 快速参考

std::max_element: https://en.cppreference.com/w/cpp/algorithm/max_element

std::lower_bound: https://en.cppreference.com/w/cpp/algorithm/lower_bound

std::upper_bound: https://zh.cppreference.com/w/cpp/algorithm/upper_bound

结语

第八十八篇博文写完,开心!!!!

今天,也是充满希望的一天。