15三数之和
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> res;
for(int i=0;i<nums.size();i++){
if(i>0 && nums[i]==nums[i-1]) continue; //重复的元素不需要再来一遍
for(int j=i+1,k=nums.size()-1;j<k;j++){
if(j>i+1 &&nums[j]==nums[j-1]) continue; //同样重复的元素不需要再枚举
while(j < k-1 && nums[i]+nums[j]+nums[k]>0) k--;
if(nums[i]+nums[j]+nums[k]==0) res.push_back({nums[i],nums[j],nums[k]});
}
}
return res;
}
};
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> res;
for(int i=0;i<nums.size();i++){
if(i>0 && nums[i]==nums[i-1]) continue;
for(int j=i+1,k=nums.size()-1;j<k;j++){
if(j>i+1 && nums[j]==nums[j-1]) continue;
while(k-1 > j && nums[i]+nums[j]+nums[k-1]>=0) k--;
if(nums[i]+nums[j]+nums[k]==0){
res.push_back({nums[i],nums[j],nums[k]});
}
}
}
return res;
}
};
18四数之和
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
for (int i = 0; i < nums.size(); i ++ ) {
if (i && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < nums.size(); j ++ ) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
for (int k = j + 1, u = nums.size() - 1; k < u; k ++ ) {
if (k > j + 1 && nums[k] == nums[k - 1]) continue;
while (u - 1 > k && nums[i] + nums[j] - target >= -nums[k] - nums[u - 1]) u -- ;
//这里是nums[i]+nums[j]+nums[k]+nums[u-1]>=target为了防止溢出,给方程做了变形
if (nums[i]+nums[j]-target==-nums[k]-nums[u]) {
//这里是nums[i]+nums[j]+nums[k]+nums[u-1]==target为了防止溢出,给方程做了变形
res.push_back({nums[i], nums[j], nums[k], nums[u]});
}
}
}
}
return res;
}
};
16最接近的三数之和
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
pair<int,int>res(INT_MAX,INT_MAX); //第一个存储的是target-s的差值,第二个是s
for(int i=0;i<nums.size();i++)
{
for(int j=i+1,k=nums.size()-1;j<k;j++)
{
while(j<k-1&&nums[i]+nums[j]+nums[k-1]>target) k--; //要找到满足最小的k
int s=nums[i]+nums[j]+nums[k];
//之所以s-target<0 是因为while的判断里有两个条件,循环退出时有可能是第一个条件不满足。
res=min(res,make_pair(abs(s-target),s));
if (k - 1 > j)
{
s = nums[i] + nums[j] + nums[k - 1];
res = min(res, make_pair(target - s, s));
}
}
}
return res.second;
}
};
17电话号码的组合(dfs)
class Solution {
public:
string strs[10] = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
vector<string> res;
void dfs(string& digits,int level,string path){
if(level==digits.size()){
res.push_back(path);
return;
}
int now_num = digits[level] - '0';
for(int i=0;i<strs[now_num].size();i++){
dfs(digits,level+1,path+strs[now_num][i]);
}
}
vector<string> letterCombinations(string digits) {
if(digits.empty()) return res;
dfs(digits,0,"");
return res;
}
};
18括号生成
class Solution {
public:
vector<string> res;
void dfs(string seq,int left_num,int right_num,int n){
//left_num是当前已经有的左括号数量,right_num是当前已经有的右括号的数量
//seq是当前已经序列
if(left_num==n && right_num==n){
res.push_back(seq);
return;
}
//因为我们只有在左括号数量大于右括号的时候才会放置右括号
if(left_num<n) dfs(seq+'(',left_num+1,right_num,n);
if(right_num<n && right_num < left_num) dfs(seq+')',left_num,right_num+1,n);
}
vector<string> generateParenthesis(int n) {
dfs("",0,0,n);
return res;
}
};
23合并k个升序链表
/**
* 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) {}
* };
*/
//优先级队列的用法:
//priority_queue<Type, Container, Functional>
//对于基础类型 默认是大顶堆
//priority_queue<int> a;
//等同于 priority_queue<int, vector<int>, less<int> > a;
//priority_queue<int, vector<int>, greater<int> > c; //这样就是小顶堆
struct cmp{
bool operator () (ListNode* a,ListNode* b){
return a->val > b->val;//这么写是小根堆
}
};
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*,vector<ListNode*>,cmp> heap;
ListNode* dummy = new ListNode(-1); //创建虚拟头节点
ListNode* now_node = dummy;
for(auto node:lists){
if(node!=NULL) heap.push(node);//先把每个链的第一个节点放进去
}
while(!heap.empty())
{
ListNode* t = heap.top();
now_node->next = t;
now_node = now_node->next;
if(t->next != NULL) heap.push(t->next);
heap.pop();
}
return dummy->next;
}
};
39组合求和(dfs)
不会有重复的元素,每个元素可以选择无限次
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void dfs(vector<int>& candidates,int target,int u)//u表示当前搜索到第几个点了
{
//每次搜到一个值就从target里面减去
if(target==0){//target减到0的时候表示是一个合法方案
res.push_back(path);
return;
}
if(u==candidates.size()) return;
//搜索完所有节点但是都没有满足target==0
//每个数可以取用多次,i表示这个数被取用几次
for(int i=0;candidates[u]*i<=target;i++)
{
if(i!=0) path.push_back(candidates[u]);
dfs(candidates,target-candidates[u]*i,u+1);
}
//恢复现场
for(int i=0;candidates[u]*i<=target;i++)
{
if(i!=0) path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
dfs(candidates,target,0);
return res;
}
};
40组合总和II
包含了重复的元素,每个元素只能够被选择1次
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
//这题与上一题的区别就是这题每个数只能用一次,但是这个数在这个数组里可能出现多次
//所以可以把元素出现的次数求出来,就转化为上一个题了
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
dfs(candidates,0,target);
return res;
}
//u这里仅仅是每个元素在candidates中第一次出现的位置
void dfs(vector<int>& candidates,int u,int target)
{
if(target==0){
res.push_back(path);
return;
}
if(u==candidates.size()) return;
int k = u+1;
while(k < candidates.size() && candidates[k]==candidates[k-1]) k++;
int cnt = k - u; //cnt即为这个元素在数组中出现的次数
for(int i=0;i*candidates[u]<=target && i<=cnt; i++){
if(i!=0) path.push_back(candidates[u]);
dfs(candidates,u+cnt,target-candidates[u]*i);
}
for(int i=0;i*candidates[u]<=target && i<=cnt; i++){
if(i>0) path.pop_back();
}
}
};
42接雨水(dp优化)
每个柱子计算其这个柱子的上方能够存储的水量,这个柱子上方能够存储的水量是由这个柱子左侧最高柱子和右侧最高柱子中的最小值决定的,最后答案只需要把所有柱子上方的存水量加起来就是最终答案。
暴力求i号柱子左右两边最大柱高O(n^2)
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if(n==0) return 0;
//求i号柱子左侧最高的柱子高度 和 右侧最高的柱子高度
map<int,int> left_max,right_max;
left_max[0] = 0;
right_max[n-1] = 0;
for(int i=1;i<height.size();i++)
{
int res = -1;
for(int j=0;j<i;j++){
res = max(res,height[j]);
}
left_max[i] = res;
}
for(int i=n-2;i>=0;i--){
int res = -1;
for(int j=i+1;j<n;j++){
res = max(res,height[j]);
}
right_max[i] = res;
}
//我们看每一个柱子能够积水的数量,就是看i号柱子这一列上面最多能够积攒多少水
//最后每一列上面能够积攒的水的数目加起来就是答案
int res = 0;
for(int i=0;i<n;i++){
res+=max(0,min(left_max[i],right_max[i])-height[i]);//只有左右最小柱高度大于当前柱高height[i]时,才能积水
}
return res;
}
};
优化求左右两端最高柱子
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if(n==0) return 0;
//求i号柱子左侧最高的柱子高度 和 右侧最高的柱子高度
//用动态规划优化一下,求i号柱子左右两部分最高柱子高度
vector<int> left_max(n),right_max(n);
//left_num[i]表示i号柱子左侧的最高柱子高度
left_max[0] = 0;
right_max[n-1] = 0;
for(int i = 1;i<n;i++) left_max[i] = max(left_max[i-1],height[i-1]);
for(int i = n-2;i>=0;i--) right_max[i] = max(right_max[i+1],height[i+1]);
//我们看每一个柱子能够积水的数量,就是看i号柱子这一列上面最多能够积攒多少水
//最后每一列上面能够积攒的水的数目加起来就是答案
int res = 0;
for(int i=0;i<n;i++){
res+=max(0,min(left_max[i],right_max[i])-height[i]);//只有左右最小柱高度大于当前柱高height[i]时,才能积水
}
return res;
}
};
45跳跃游戏II(dp)
f[i] 表示从0号点到i号点能够跳跃的方案集合
属性 min, 跳跃次数最小值
显然f[0] = 0 ,f[1] = 1
并且一定有 f[i] <= f[i+1]
证明:
假设 f[i] > f[ i + 1 ]
那么必定有一个点k(k<i)使得i+1点是从k点跳过来的(显然这样不可能k=i,这样的话f[i+1] > f[i])
但是既然 k 点能够跳到i+1点,那么k点也一定能够跳到i点,那么此时f[i]就可以变成从k点跳过来,此时就找到了一个比上一个f[i]更小值的步数,且这个步数最大等于f[i+1],也就是推出f[i]<=f[i+1]
与假设矛盾,所以 f[i] > f[i+1] 不成立
综上所述: f[i] <= f[i+1]
因为有 f[i] <= f[i+1]的性质存在
而 f[i] = f[j]+1 所以我们找到一个尽可能远离i的j最好
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
vector<int> f(n+1);
f[0] = 0;
int last_node = 0;
for(int i=1;i<n;i++){
while(last_node + nums[last_node] < i) last_node++;
//因为有 f[i] <= f[i+1]的性质存在
//而 f[i] = f[j]+1 所以我们找到一个尽可能远离i的j最好
f[i] = f[last_node] + 1;
}
return f[n-1];
}
};
跳跃游戏(贪心)
class Solution {
public:
bool canJump(vector<int>& nums) {
int max_length = 0; //max_length表示能够跳跃的最大的长度
for(int i=0;i<nums.size();i++){
if(max_length < i) return false;//如果跳不到i了直接返回false
max_length = max(max_length,i+nums[i]);
}
return true;
}
};
46,47全排列(dfs)
这个题不含有重复的元素
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
map<int,bool> st;
void dfs(vector<int>& nums,int depth)
{
if(depth==nums.size()){
res.push_back(path);
return;
}
for(int i=0;i<nums.size();i++){
if(st[nums[i]]) continue;
st[nums[i]] = true;
path.push_back(nums[i]);
dfs(nums,depth+1);
path.pop_back();
st[nums[i]] = false;
}
}
vector<vector<int>> permute(vector<int>& nums) {
int n = nums.size();
for(int i=0;i<n;i++) st[nums[i]] = false;
dfs(nums,0);
return res;
}
};
这个题含有重复的元素
总而言之,为了避免重复序列的出现,对于比如nums中有 1 1 1
那么当第一个1被用了之后,第二个1我们让他只能够排在第一个1的后面,同理,第三个1只能排在第二个1的后面
也就是每一次排一个数的时候,看一下这个数有没有被用过
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<bool> st;
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
st = vector<bool>(nums.size(),false);
path = vector<int>(nums.size());
dfs(nums,0);
return res;
}
void dfs(vector<int>& nums,int u)//u代表当前已经排列完几个节点了
{
if(u==nums.size()){
res.push_back(path);
return;
}
for(int i=0;i<nums.size();i++){
if(!st[i]){//首先nums中的i号节点需要先没用过才行
//如果nums[i]不是这个数值第一次被用,那么就先不排
//就是比如说有 1 1 1 2 2 这样的我们每次用的1都是1 1 1 按顺序使用的
// 必须先用没用过的1 再用下面的
if(i>0 && nums[i]==nums[i-1] && !st[i-1]) continue;
//只有这个数值是第一次被排列我们才去排列
//换言之,如果这个数是此数值序列中的第一个
//或者这个数值不是序列中此类数值的第一个,但是这个数的前一个数i-1已经被排过了
//我们就可以继续排i号这个数了
st[i] = true;
path[u] = nums[i];
dfs(nums,u+1);
st[i] = false;
}
}
}
};
class Solution {
public:
vector<bool> st;
vector<int> ans;
vector<vector<int>> res;
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(),nums.end());
st = vector<bool>(n,false);
dfs(nums,0);
return res;
}
void dfs(vector<int>& nums, int u)
{
if(u==nums.size())
{
res.push_back(ans);
return;
}
for(int i=0;i<nums.size();i++){
if(st[i]) continue;
if(i > 0 && nums[i]==nums[i-1] && !st[i-1]) continue;
ans.push_back(nums[i]);
st[i] = true;
dfs(nums,u+1);
st[i] = false;
ans.pop_back();
}
}
};
50 POW(x,n)
class Solution {
public:
double myPow(double x, int n) {
typedef long long LL;
bool flag = false;
if(n==0) return 1;
if(n<0) flag = true;
double res = 1;
for(LL k = abs(LL(n));k;k>>=1)
{
if(k & 1) res *= x;//注意是k&1不是k&&1,看写成二进制的n的最后一位是0还是1
x*=x; //x记录的是 x^(2^i)
}
if(flag) res = 1/res;
return res;
}
};
n皇后(dfs)
class Solution {
public:
int n;
vector<bool> row;
vector<bool> col;
vector<bool> dg;
vector<bool> rdg;
vector<vector<string>> res;
vector<string> path;
vector<vector<string>> solveNQueens(int _n) {
n = _n;
row = vector<bool>(n);
col = vector<bool>(n);
dg = vector<bool>(2*n);
rdg = vector<bool>(2*n);
path = vector<string>(n,string(n,'.'));
dfs(0);
return res;
}
void dfs(int u){//u表示现在搜索到第几行了
if(u==n){
res.push_back(path);
return;
}
//遍历这一行上的每个位置
for(int i=0;i<n;i++){
if(!col[i] && !row[u] && !dg[u+i] && !rdg[u-i+n]){
col[i] = true;
row[u] = true;
dg[u+i] = true;
rdg[u-i+n] = true;
path[u][i] = 'Q';
dfs(u+1);
col[i] = false;
row[u] = false;
dg[u+i] = false;
rdg[u-i+n] = false;
path[u][i] = '.';
}
}
}
};
class Solution {
public:
int n;
vector<bool> row;
vector<bool> col;
vector<bool> dg;
vector<bool> rdg;
vector<vector<string>> res;
vector<string> path;
int totalNQueens(int _n) {
n = _n;
row = vector<bool>(n);
col = vector<bool>(n);
dg = vector<bool>(2*n);
rdg = vector<bool>(2*n);
path = vector<string>(n,string(n,'.'));
dfs(0);
return res.size();
}
void dfs(int u){//u表示现在搜索到第几行了
if(u==n){
res.push_back(path);
return;
}
//遍历这一行上的每个位置
for(int i=0;i<n;i++){
if(!col[i] && !row[u] && !dg[u+i] && !rdg[u-i+n]){
col[i] = true;
row[u] = true;
dg[u+i] = true;
rdg[u-i+n] = true;
path[u][i] = 'Q';
dfs(u+1);
col[i] = false;
row[u] = false;
dg[u+i] = false;
rdg[u-i+n] = false;
path[u][i] = '.';
}
}
}
};
最大子序和(dp)
f[ i ] 表示所有以nums[ i ]结尾的区间的集合方案的最大值
这个集合又可划分为两大类,区间长度为1(即包含nums[i]这个数)
区间长度大于1
class Solution {
public:
vector<int> f;
int maxSubArray(vector<int>& nums) {
int n = nums.size();
f = vector<int>(n);
f[0] = nums[0];
for(int i=1;i<n;i++){
f[i] = max(nums[i],f[i-1]+nums[i]);
}
int res = -1e5;
for(int i=0;i<n;i++) res = max(res,f[i]);
return res;
}
};
当还要输出这个序列起始和终止的数字时
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e4 + 10;
int n;
int nums[N];
int f[N],i_left[N]; //f[i]表示以nums[i]结尾的序列最大和
//left[i]表示以nums[i]结尾的序列的起始位置
int main()
{
cin >> n;
for(int i=0;i<n;i++) cin >> nums[i];
f[0] = nums[0];
i_left[0] = 0;
int res = -1;
int l,r;
for(int i=1;i<n;i++){
f[i] = nums[i];
i_left[i] = i;
if(f[i-1]+nums[i] >= f[i]){
f[i] = f[i-1] + nums[i];
i_left[i] = i_left[i-1];
}
if(f[i] > res){
res = f[i];
l = nums[i_left[i]];
r = nums[i];
}
}
if(res < 0){
res = 0;
l = nums[0];
r = nums[n-1];
}
cout << res <<" "<<l << " "<< r << endl;
return 0;
}
第k个排列
这种搜索方法排出来的本来就是按照字典序排的了
class Solution {
public:
vector<string> res;
string path;
vector<bool> st;
int n;
string getPermutation(int _n, int k) {
n = _n;
st = vector<bool>(n+1,false);
dfs(0);
return res[k-1];
}
void dfs(int u)
{
if(u==n){
res.push_back(path);
return;
}
for(int i=1;i<=n;i++){
if(st[i]) continue;
st[i] = true;
path.push_back(i + '0');
dfs(u+1);
path.pop_back();
st[i] = false;
}
}
};
62不同路径(dp)
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> f(m, vector<int>(n, 0)); // 初始化为 0
for(int i=0;i<n;i++) f[0][i] = 1;
for(int i=0;i<m;i++) f[i][0] = 1;
for(int i = 1; i < m; i++ )
for(int j = 1;j<n;j++)
f[i][j] = f[i-1][j] + f[i][j-1];
return f[m-1][n-1];
}
};
本题与上题的区别就是有的方格有障碍物的存在
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
vector<vector<int>> f(m,vector<int>(n,0));
for(int i=0;i<m;i++){
if(obstacleGrid[i][0]==1) break;//之后的格子都到不了了,都设置成0
f[i][0] = 1;
}
for(int i=0;i<n;i++){
if(obstacleGrid[0][i]==1) break;
f[0][i] = 1;
}
//只需要判断一下这个格子是不是障碍物,是的话设为0,否则设为f[i-1][j]+f[i][j-1]
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
if(obstacleGrid[i][j]==1) f[i][j] = 0;
else{
f[i][j] = f[i-1][j] + f[i][j-1];
}
}
}
return f[m-1][n-1];
}
};
64最小路径和(dp)
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
vector<vector<int>> f(m,vector<int>(n,0));
f[0][0] = grid[0][0];
for(int i=1;i<m;i++) f[i][0] = f[i-1][0] + grid[i][0];
for(int i=1;i<n;i++) f[0][i] = f[0][i-1] + grid[0][i];
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
f[i][j] = min(f[i-1][j],f[i][j-1]) + grid[i][j];
}
}
return f[m-1][n-1];
}
};
97复原IP地址
class Solution {
public:
vector<string> res;
vector<string> restoreIpAddresses(string s) {
dfs(s,0,0,"");
return res;
}
//u表示当前搜索到了哪一个位置,k表示当前已经分割出了几个数字
void dfs(string& s,int u,int k,string path)
{
if(u==s.size()){
if(k==4){
path.pop_back();
res.push_back(path);
}
return;
}
if(u!=s.size() && k==4) return; //如果已经得到四部分数字但是却还没划分完成直接剪枝
int num = 0;
for(int i = u; i < s.size(); i++)
{
if(i>u && s[u]=='0') break;
num = num*10 + s[i]-'0';
if(num<=255) dfs(s,i+1,k+1,path + to_string(num) + '.');
else break;
}
}
};
71简化路径
/***
我们先把两个 / / 之间的内容取出来,那么取出来的内容总共有几种情况:
. , .. , file_name , 空
如果/ / 之间的是空或者.那么不做操作
如果读出来的是文件名,入栈
如果读出来的是.. 如果栈不为空就退栈
最后栈中的元素就是当前的文件路径
***/
class Solution {
public:
string simplifyPath(string path) {
int n = path.size();
vector<string> res;
stack<string> st;
for(int i=0;i<n;)
{
string temp = "";
int j = i + 1;
while(j < n && path[j] != '/') temp += path[j++];
i = j;
res.push_back(temp);
}
for(int i=0;i<res.size();i++){
if(res[i] == "" || res[i]==".") continue;
else if(res[i] == ".."){
if(!st.empty()) st.pop();
}
else st.push(res[i]);
}
string ans = "";
while(!st.empty()){
ans = "/" + st.top() + ans;
st.pop();
}
if(ans=="") ans = "/";
return ans;
}
};
74搜索二维矩阵
/***
考虑把这个矩阵虚拟展开成一个一维的矩阵然后就可以用二分来做了
总共0~mn-1个位置
然后对于在一维数组中的 i 号位置影射到二维数组中的位置就是 (i/m,i%m)
***/
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.empty() || matrix[0].empty()) return false;
int n = matrix.size();
int m = matrix[0].size();
int l = 0, r = m*n-1;
while(l < r)
{
int mid = (l+r)/2;
if(matrix[mid/m][mid%m] >= target) r = mid;
else l = mid + 1;
}
if(matrix[r/m][r%m]==target) return true;
return false;
}
};
75颜色分类
总的来说就是用三个指针来维护,j指向第一个1出现的位置, 0 ~ j-1 都是0
k指向2的部分的前一个位置也就是说 k+1 ~ nums.size()-1 这些位置都是2
我们用i来扫描数组
如果nums[i] = 0 , 那么swap(nums[j], nums[i]) 然后j++ , i++
如果nums[i] = 2, 那么swap(nums[i], nums[k]) 然后k–,此时就不要i++了,因为我们交换过来的东西可能是0,不一定是1
如果nums[i] = 1 , 那么i++即可
然后最终i = k + 1的时候就结束了(注意i=k的时候还不能结束,因为有可能k指向的这个位置他是0还得再换一次,即使是1那么也无妨再i++后当i = k+1时退出即可)
class Solution {
public:
void sortColors(vector<int>& nums) {
for(int i=0,j=0,k=nums.size()-1;i<=k;)
{
if(nums[i]==0) swap(nums[i++],nums[j++]);
else if(nums[i]==2) swap(nums[i],nums[k--]);
else i++;
}
}
};
77组合
/***
组合问题比较麻烦的地方在于判重问题,但是我们可以规定某种选取规则,比如选的数不能比之前选的数小
***/
class Solution {
public:
vector<int> ans;
vector<vector<int>> res;
vector<vector<int>> combine(int n, int k) {
dfs(n,k,1);
return res;
}
void dfs(int n,int k,int start)
{//n表示从1~n中选, k 表示还能够选的数的个数, start表示最小从这个数开始选
if(k==0)
{
res.push_back(ans);
return;
}
for(int i=start;i<=n;i++){
ans.push_back(i);
dfs(n,k-1,i+1);
ans.pop_back();
}
}
};
78子集
class Solution {
public:
vector<int> ans;
vector<vector<int>> res;
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums,0);
return res;
}
void dfs(vector<int>& nums,int depth)
{
if(depth==nums.size())
{
res.push_back(ans);
return;
}
dfs(nums,depth+1); //不选这个数
ans.push_back(nums[depth]); //选这个数
dfs(nums,depth+1);
ans.pop_back();
}
};