给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
回溯算法:维护走过的路径,当前可以做的选择列表,当触发结束条件时,将路径记入结果集 ,回溯函数(记录的路径,可以选择的路径) res是个全局的变量
class Solution {
public:
void backtrack(vector<vector<int>> &res,vector<int>& nums, vector<int> tarck)
{
//结束条件
if(tarck.size() == nums.size())
{
res.push_back(tarck);//一个进去
}
//回溯的套路 遍历选择列表
for(int i = 0; i<nums.size(); i++)
{
if(std::find(tarck.begin(), tarck.end(), nums[i]) != tarck.end()) //已经存在 跳过
continue;
//加入
tarck.push_back(nums[i]);
//进入下一层循环树
backtrack(res, nums, tarck);
tarck.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<int> tarck;//记录的路径
vector<vector<int>> res;//保存的路径
backtrack(res, nums, tarck);//nums选择的路径
return res;
}
};
需要遍历所有解,所以还是回溯的做法
结束条件是到digits的最后一个,每一个字符完成就是一个track(保存的路径),注意这个遍历是要添加下一个字符对应数据中的数字,所以要注意digits中下标的更新,感觉做回溯就是不要想太多(也可能是我理解还没有太到位,不然就容易陷进去,递归的痛==)
class Solution {
public:
unordered_map<char, string> phoneMap{
{'2', "abc"},
{'3', "def"},
{'4', "ghi"},
{'5', "jkl"},
{'6', "mno"},
{'7', "pqrs"},
{'8', "tuv"},
{'9', "wxyz"}
};
void backtrack(vector<string>& res,string tarck, string digits, int i)
{
//结束条件 digits遍历完
if(i == digits.size())
{
res.push_back(tarck);
}
char digit = digits[i];
string letters = phoneMap[digit];
//遍历可以选择的路径
for(auto letter : letters)
{
tarck.push_back(letter);//加
backtrack(res, tarck, digits, i+1);//下一个决策树
tarck.pop_back();//撤销
}
}
vector<string> letterCombinations(string digits) {
//回溯 寻找所有可行解
vector<string> res;
if(digits.empty())
return res;
string tarck;//记录的值
// int i = 0;
backtrack(res, tarck, digits, 0);
return res;
}
};
给你一个由 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最前面几个已经大于target了 下一个2 最后几个数相加依然小于target 下一个
代码思路还是挺清晰的,但是要注意程序溢出的问题 int
—long
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
if (nums.size() < 4) {
return res;
}
sort(nums.begin(), nums.end());
int n = nums.size();
for(int i = 0; i<nums.size()-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)
continue;
if((long)nums[i] + nums[n-3] + nums[n-1] + nums[n-2] < target)
continue;
//循环另一个数
for(int j = i+1; j<n-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[n-1] + nums[n-2] < target)
continue;
int left = j+1; int right = n-1;
while(left < right)
{
long curSum = (long)nums[i] + nums[j] + nums[left] + nums[right];
if(curSum == target)
{
res.push_back({nums[i], nums[j], nums[left], nums[right]});
//当前组ok 开始下一组
//先把重复的元素去掉
while(left< right && nums[left]==nums[left+1])
{
left++;
}
left++;//下一个元素不一样了 到不一样的元素这儿
while(left<right && nums[right] == nums[right-1])
{
right--;
}
right--;//right肯定也要变 不变的话这三个数固定了 另一个数肯定是原来的left
}
//当前组不满足 那么根据当前和进行指针的移动
if(curSum>target)
{
right--;
}
else if(curSum<target)
{
left++;
}
}
}
}
return res;
}
};
//[-2 -1 0 0 1 2] 排序有什么好处 如何去重
//"为了避免枚举到重复,需要保证每一重循环枚举到的元素 不小于 上一重循环枚举到的元素 且在同一重循环中不能多次枚举到相同的元素"?
//使用两重循环分别枚举前两个数,再使用双指针枚举剩下的两个数
//剪枝操作