- 15. 三数之和 中等
- 20. 有效的括号 简单
- 75. 颜色分类 中等
- 136. 只出现一次的数字 简单
- 155. 最小栈 中等
- 169. 多数元素 简单
- 283. 移动零 简单
- 448. 找到所有数组中消失的数字 简单
- 461. 汉明距离 简单

解法1: 排序+双指针

class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
if(nums.size()<3) return ans;
sort(nums.begin(), nums.end());
if(nums[0]>0) return ans;
int i = 0;
while(i<nums.size()){
if(nums[i]>0) break;
int left = i+1, right = nums.size()-1;
while(left< right){
long long y = static_cast<long long>(nums[i]);
long long x = static_cast<long long>(nums[left]);
long long z = static_cast<long long>(nums[right]);
if(x + y >0-z)
right--;
else if(x + y <0-z)
left++;
else{
ans.push_back({nums[i], nums[left], nums[right]});
while(left<right&&nums[left]==nums[left+1])
left++;
while(left<right&&nums[right] == nums[right-1])
right--;
left++;
right--;
}
}
while(i+1<nums.size()&&nums[i] == nums[i+1])
i++;
i++;
}
return ans;
}
};


解法1: 辅助栈
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();
}
};
- 时间复杂度:O(n), 其中 n 是字符串 s 的长度
- 空间复杂度:O(n+∣Σ∣), 其中 Σ 表示字符集,本题中字符串只包含 6 种括号,∣Σ∣=6。栈中的字符数量为 O(n),而哈希表使用的空间为 O(∣Σ∣),相加即可得到总空间复杂度.

解法1: 单指针
- 对数组进行两次遍历
- 第一次遍历, 将数组所有的0交换到数组的头部
- 第二次遍历, 将数组所有的1交换到头部0之后
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size()
int ptr = 0
for (int i = 0
if (nums[i] == 0) {
swap(nums[i], nums[ptr])
++ptr
}
}
for (int i = ptr
if (nums[i] == 1) {
swap(nums[i], nums[ptr])
++ptr
}
}
}
}
- 时间复杂度:O(n), n为数组长度
- 空间复杂度:O(1)
解法2: 双指针
- 从左向右遍历数组
- 用指针p0 交换 0, p1 交换 1, 初始值为0
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size()
int p0 = 0, p1 = 0
for (int i = 0
if (nums[i] == 1) {
swap(nums[i], nums[p1])
++p1
} else if (nums[i] == 0) {
swap(nums[i], nums[p0])
if (p0 < p1) {
swap(nums[i], nums[p1])
}
++p0
++p1
}
}
}
}
- 时间复杂度:O(n), n为数组长度
- 空间复杂度:O(1)
解法3: 双指针
- 用指针 p0 交换0,p2 交换2
- p0初始值为0, p2初始值为n-1
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size()
int p0 = 0, p2 = n - 1
for (int i = 0
while (i <= p2 && nums[i] == 2) {
swap(nums[i], nums[p2])
--p2
}
if (nums[i] == 0) {
swap(nums[i], nums[p0])
++p0
}
}
}
}
- 时间复杂度:O(n), n为数组长度
- 空间复杂度:O(1)

解法1:内置位计数功能
class Solution {
public:
int hammingDistance(int x, int y) {
return __builtin_popcount(x ^ y);
}
};
- 时间复杂度:O(1). 不同语言的实现方法不一,我们可以近似认为其时间复杂度为 O(1)
- 空间复杂度:O(1)
解法2:内置位计数功能

class Solution {
public:
int hammingDistance(int x, int y) {
int s = x ^ y, ret = 0;
while (s) {
ret += s & 1;
s >>= 1;
}
return ret;
}
};
- 时间复杂度:O(logC), 其中 C 是元素的数据范围,在本题中 logC=log231=31logC=log231=31。
- 空间复杂度:O(1)
136. 只出现一次的数字

解法1: 位运算
- 任何数和 0 做异或运算,结果仍然是原来的数,即 a⊕0=a
- 任何数和其自身做异或运算,结果是 00,即 a⊕a=0

class Solution {
public int singleNumber(int[] nums) {
int single = 0;
for (int num : nums) {
single ^= num;
}
return single;
}
}
- 时间复杂度:O(n),其中 n 是数组长度。只需要对数组遍历一次
- 空间复杂度:O(1)

解法一:辅助栈
- 定义一个
辅助栈x_stack, 各一个最小栈min_stack
- 当一个元素要入栈时,我们取当前
辅助栈的栈顶存储的最小值,与当前元素比较得出最小值,将这个最小值插入辅助栈中
- 当一个元素要出栈时,我们把辅助栈的栈顶元素也一并弹出
- 在任意一个时刻,栈内元素的最小值就存储在辅助栈的
栈顶元素中
class MinStack {
stack<int> x_stack;
stack<int> min_stack;
public:
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();
}
};
- 时间复杂度:O(1), 因为栈的插入、删除与读取操作都是 O(1),我们定义的每个操作最多调用栈操作两次
- 空间复杂度:O(n), 其中 n 为总操作数。最坏情况下,我们会连续插入 n 个元素,此时两个栈占用的空间为 O(n)

解法1: 哈希表
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int, int> counts
int majority = 0, cnt = 0
for (int num: nums) {
++counts[num]
if (counts[num] > cnt) {
majority = num
cnt = counts[num]
}
}
return majority
}
}
- 时间复杂度:O(n), 其中 n 是数组
nums 的长度。我们遍历数组 nums 一次,对于 nums 中的每一个元素,将其插入哈希表都只需要常数时间
- 空间复杂度:


解法1: 双指针
- 使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部
- 右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移
- 左指针左边均为非零数
- 右指针左边直到左指针处均为零
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++;
}
}
};
- 时间复杂度:O(n), 其中 n 为序列长度。每个位置至多被遍历两次
- 空间复杂度:O(1)

class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int n = nums.size()
for (auto& num : nums) {
int x = (num - 1) % n
nums[x] += n
}
vector<int> ret
for (int i = 0
if (nums[i] <= n) {
ret.push_back(i + 1)
}
}
return ret
}
}
- 时间复杂度:O(n),其中 n 是数组长度。只需要对数组遍历一次
- 空间复杂度:O(1)