开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!
Leetcode学习之递归、回溯与分治(2)
题目来源: L e e t c o d e 22. S u b s e t s Leetcode \ 22. \ Subsets Leetcode 22. Subsets
题目描述:已知n组括号,开发一个程序,生成这N组括号的所有合法的组合可能。
要求描述:
分析:
预备知识思路:递归生成所有可能。
测试代码:
#include
#include
#include
using namespace std;
//item生成括号字符串,n为组数,result为最终结果
void generate(string item, int n, vector<string> &result) {
if (item.size() == 2*n) {//字符串括号的长度为2n,结束递归
result.push_back(item);
return;
}
generate(item + '(', n, result);//添加'('字符,继续递归
generate(item + ')', n, result);//添加')'字符,继续递归
}
int main() {
vector<string> result;
generate("", 2, result);
for (int i = 0; i < result.size(); i++) {
printf("%s", result[i].c_str());
printf("\n");
}
system("pause");
return 0;
}
#include
#include
using namespace std;
class Solution {
public:
vector<string> generateParentthesis(int n) {
vector<string> result;
generate("", n,n,result);//n,n表示放置左括号的数目,放置右括号的数目
return result;
}
private:
void generate(string item, int left, int right, vector<string> &result) {//item表示生成的字符串
if (left == 0 && right == 0) {
result.push_back(item);
return;
}
if (left > 0) { //左边
generate(item + '(', left - 1, right, result);
}
if (left < right) { //左边的数量 <= 右边的数量,才可以进行有括号的放置
generate(item + ')', left, right-1, result);
}
}
};
int main() {
Solution solve;
vector<string> result = solve.generateParentthesis(3);
for (int i = 0; i < result.size(); i++) {
printf("%s\n", result[i].c_str());
}
system("pause");
return 0;
}
题目来源: L e e t c o d e 51. N − Q u e e n s Leetcode \ 51. \ N-Queens Leetcode 51. N−Queens
题目描述:将N个皇后放在N*N个棋盘中,互相不可攻击,有多少摆放方式,每种摆放方式具体是怎么样的?
要求描述: 传出 N 皇后的所有结果,每个结果是一个棋盘,每个棋盘均使用字符串向量表示。
分析:棋盘与皇后表示。
测试代码:
#include
#include
using namespace std;
void put_down_the_queen(int x, int y, vector<vector<int>> &mark) {
//方向数组
static const int dx[] = { -1,1,0,0,-1,-1,1,1 };
static const int dy[] = { 0,0,-1,1,-1,1,-1,1 };
mark[x][y] = 1;//(x,y)位置上放置皇后,进行标记
for (int i = 1; i < mark.size(); i++) {//8个方向,每个方向向外延伸1至N-1
for (int j = 0; j < 8; j++) {
int new_x = x + i*dx[j];//新的位置向8个方向延伸,每个方向最多N-1
int new_y = y + i*dy[j];
//检查新位置是否还在棋盘里
if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {
mark[new_x][new_y] = 1;
}
}
}
}
#include
#include
using namespace std;
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> result;//存储最终结果的数组
vector<vector<int>> mark;//标记棋盘是否可以放置皇后的二维数组
vector<string> location;//存储某个摆放结果,当完成一次递归找到结果后,将location push进入result
//二维的vector进行push_back
/*这边网上的例子是:
vector> a;
for(int i = 0; i < 5; i++){
vector b;
a.push_back(b);
for(int j = 0; j < 4; j++){
POINT c = {i, j};
a[i].push_back(c);
}
}
*/
for (int i = 0; i < n; i++) { //这边n=4
mark.push_back(vector<int>()); //这边先将一维vector进行push_back进去
for (int j = 0; j < n; j++) {
mark[i].push_back(0);
}
location.push_back("");
location[i].append(n, '.');
}
generate(0, n, location, result, mark);
return result;
}
private:
void put_down_the_queen(int x, int y, vector<vector<int>> &mark) {
//方向数组
static const int dx[] = { -1,1,0,0,-1,-1,1,1 };
static const int dy[] = { 0,0,-1,1,-1,1,-1,1 };
mark[x][y] = 1;//(x,y)位置上放置皇后,进行标记
for (int i = 1; i < mark.size(); i++) {//8个方向,每个方向向外延伸1至N-1
for (int j = 0; j < 8; j++) {
int new_x = x + i*dx[j];
int new_y = y + i*dy[j];
//检查新位置是否还在棋盘里
if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {
mark[new_x][new_y] = 1;
}
}
}
}
void generate(int k, int n, //k代表完成几个皇后的放置(正在放置第K行皇后)
vector<string> &location, //某次结果存储在location中
vector<vector<string>> &result, //最终结果存储在result中
vector<vector<int>> &mark) {//表示棋盘的标记数据
if (k == n) {//当k==n时,代表完成第0至n-1行皇后的位置,所有皇后完成放置后,将记录皇后位置的location数组push进入result
result.push_back(location);
return;
}
for (int i = 0; i < n; i++) {//这边n=4
if (mark[k][i] == 0) {//如果maik[k][i]==0,表示可以放置皇后
vector<vector<int>> tmp_mark = mark;//记录回溯前的mark镜像
location[k][i] = 'Q';//记录当前皇后的位置
put_down_the_queen(k, i, mark);//放置皇后
generate(k + 1, n, location, result, mark);//递归下一行皇后放置
mark = tmp_mark;//将mark重新赋值为回溯前状态,这边的原因是该次递归结束后,恢复mark数组,并且尝试下一个可能放皇后的列
location[k][i] = '.';//将当前尝试的皇后位置更新为。
}
}
}
};
int main() {
vector<vector<string>> result;
Solution solve;
result = solve.solveNQueens(4);
for (int i = 0; i < result.size(); i++) {
printf("i=%d\n", i);
for (int j = 0; j < result[i].size(); j++) {
printf("%s\n", result[i][j].c_str());
}
printf("\n");
}
system("pause");
return 0;
}
题目描述:已知两个已排序的数组,将这两个数组合并成为一个排序数组。
要求描述:
测试代码:
#include
using namespace std;
void merge_sort_teo_vec(vector<int> &sub_vec1,//数组1
vector<int> &sub_vec2,//数组2
vector<int> &vec) {//合并后的数组
int i = 0, j = 0;
while (i < sub_vec1.size() && j < sub_vec2.size())
{
if (sub_vec1[i]<=sub_vec2[j])
{
vec.push_back(sub_vec1[i]);
i++;
}
else
{
vec.push_back(sub_vec2[j]);
j++;
}
}
for (; i < sub_vec1.size(); i++) {//将sub_vec1或者sub_vec2中的剩余元素push进入vec
vec.push_back(sub_vec1[i]);
}
for (; j < sub_vec2.size(); j++) {
vec.push_back(sub_vec2[j]);
}
}
int main() {
int test1[] = { 2,5,8,20 };
int test2[] = { 1,3,5,7,30,50 };
vector<int> sub_vec1;
vector<int> sub_vec2;
vector<int> sub_vec;
for (int i = 0; i < 4; i++) {
sub_vec1.push_back(test1[i]);
}
for (int i = 0; i < 4; i++) {
sub_vec2.push_back(test2[i]);
}
merge_sort_teo_vec(sub_vec1, sub_vec2,sub_vec);
for (int i = 0; i < sub_vec.size(); i++) {
printf("[%d]", sub_vec[i]);
}
printf("\n");
system("pause");
return 0;
}
#include
using namespace std;
void merge_sort_teo_vec(vector<int> &sub_vec1,//数组1
vector<int> &sub_vec2,//数组2
vector<int> &vec) {//合并后的数组
int i = 0, j = 0;
while (i < sub_vec1.size() && j < sub_vec2.size())
{
if (sub_vec1[i]<=sub_vec2[j])
{
vec.push_back(sub_vec1[i]);
i++;
}
else
{
vec.push_back(sub_vec2[j]);
j++;
}
}
for (; i < sub_vec1.size(); i++) {//将sub_vec1或者sub_vec2中的剩余元素push进入vec
vec.push_back(sub_vec1[i]);
}
for (; j < sub_vec2.size(); j++) {
vec.push_back(sub_vec2[j]);
}
}
void merge_sort(vector<int> &vec) {
if (vec.size() < 2) {
return;//当问题小于2时,就不需要分治了
}
//对原问题进行分解,即对原数组拆分为两个规模相同的数组,再对它们进行分别求解
int mid = vec.size() / 2;
vector<int> sub_vec1;
vector<int> sub_vec2;
for (int i = 0; i < mid; i++) {
sub_vec1.push_back(vec[i]);
}
for (int i = mid; i < vec.size(); i++) {
sub_vec2.push_back(vec[i]);
}
merge_sort(sub_vec1);
merge_sort(sub_vec2);//对拆解后的两个子网络进行递归求解
vec.clear();
merge_sort_teo_vec(sub_vec1, sub_vec2, vec);//合并,将子问题的解进行合并
}
int main() {
vector<int> vec;
int test[] = { 5,-7,9,8,1,4,-3,10,2,0 };
for (int i = 0; i <10; i++) {
vec.push_back(test[i]);
}
merge_sort(vec);
for (int i = 0; i <vec.size(); i++) {
printf("[%d]", vec[i]);
}
printf("\n");
system("pause");
return 0;
}
题目来源: L e e t c o d e 315. C o u n t o f S m a l l e r N u m b e r s A f t e r S e l f Leetcode \ 315. \ Count \ of \ Smaller \ Numbers \ After \ Self Leetcode 315. Count of Smaller Numbers After Self
题目描述:已知数组nums,求新数组count,count[i]代表了在nums[i]右侧且比nums[i]小的元素个数。
要求描述:
分析:
接着分析:
测试代码:
#include
using namespace std;
class Solution {
public:
vector<int> countSmaller(vector<int> &nums) {
vector<pair<int, int>> vec;//nums和count数组
vector<int> count;
for (int i = 0; i < nums.size(); i++) {
vec.push_back(make_pair(nums[i], i));//这边后面给的是编号
count.push_back(0);//count一开始全部赋值为0
}
merge_sort(vec, count);
return count;
}
private:
void merge_sort(vector<pair<int, int>> &vec, vector<int> &count) {
if (vec.size() < 2) {
return;//当问题小于2时,就不需要分治了
}
//对原问题进行分解,即对原数组拆分为两个规模相同的数组,再对它们进行分别求解
int mid = vec.size() / 2;
vector<pair<int, int>> sub_vec1;
vector<pair<int, int>> sub_vec2;
for (int i = 0; i < mid; i++) {
sub_vec1.push_back(vec[i]);
}
for (int i = mid; i < vec.size(); i++) {
sub_vec2.push_back(vec[i]);
}
merge_sort(sub_vec1, count);
merge_sort(sub_vec2, count);//对拆解后的两个子网络进行递归求解
vec.clear();
merge_sort_teo_vec(sub_vec1, sub_vec2, vec, count);//合并,将子问题的解进行合并
}
void merge_sort_teo_vec(vector<pair<int, int>> &sub_vec1,//数组1
vector<pair<int, int>> &sub_vec2,//数组2
vector<pair<int, int>> &vec,//合并后的数组
vector<int> &count) {
int i = 0, j = 0;
while (i < sub_vec1.size() && j < sub_vec2.size())
{
if (sub_vec1[i].first <= sub_vec2[j].first)
{
count[sub_vec1[i].second] += j;//这边改变对应的count数组的值,这边加j的原因前面分析了,重要哦!
vec.push_back(sub_vec1[i]);
i++;
}
else
{
vec.push_back(sub_vec2[j]);
j++;
}
}
for (; i < sub_vec1.size(); i++) {//将sub_vec1或者sub_vec2中的剩余元素push进入vec
count[sub_vec1[i].second] += j;
vec.push_back(sub_vec1[i]);
}
for (; j < sub_vec2.size(); j++) {
vec.push_back(sub_vec2[j]);
}
}
};
int main() {
int test[] = { 5,-7,9,1,3,5,-2,1 };
vector<int> nums; //输入数据
for (int i = 0; i < 8; i++) {
nums.push_back(test[i]);
}
Solution solve;
vector<int> result = solve.countSmaller(nums);
for (int i = 0; i < result.size(); i++) {
printf("[%d]", result[i]);
}
printf("\n");
system("pause");
return 0;
}