都是直接dfs,算是巩固一下

电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

思路

一直搜索,到终点判断是否已经出现,未出现则加入集合

代码

class Solution {
set<string>s;
map<char,string>m;
public: void dfs(string d, string cur, int step){
if(step>d.size()){
return;
}
if(step==d.size()){
if(s.count(cur)>0){
return;
}else{
s.insert(cur);
}
}
string tmp=m[d[step]];
for(int i=0;i<tmp.size();++i){
dfs(d,cur+tmp[i],step+1);
}
} vector<string> letterCombinations(string digits) {
m.insert(make_pair('2',"abc"));
m.insert(make_pair('3',"def"));
m.insert(make_pair('4',"ghi"));
m.insert(make_pair('5',"jkl"));
m.insert(make_pair('6',"mno"));
m.insert(make_pair('7',"pqrs"));
m.insert(make_pair('8',"tuv"));
m.insert(make_pair('9',"wxyz"));
string s1;
vector<string>ans;
if(digits.size()==0){
return ans;
}
dfs(digits,s1,0);
for(auto i = s.begin(); i!=s.end();++i){
ans.push_back(*i);
}
return ans;
}
};

生成括号

给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

例如,给出 n = 3,生成结果为:

[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]

思路

第一个肯定是左括号,接着搜索,每个位置可能是"("或者")",搜索时注意左右括号的数量关系

代码

class Solution {
vector<string>ans;
bool ok(const string&s){
stack<char>st;
for(int i=0;i<s.size();++i){
if(s[i]=='('){
st.push(s[i]);
}else{
if(st.empty()){
return false;
}else{
char c=st.top();
if(c!='(')return false;
else st.pop();
}
}
}
return st.empty();
}
public:
void dfs(string cur,int L,int R,int total){
if(L+R>total)return;
if(abs(L-R)>total-L-R)return;
if(L+R==total){
if(L!=R){
return;
}else{
if(ok(cur)){
ans.push_back(cur);
}
return;
}
}
dfs(cur+'(',L+1,R,total);
dfs(cur+')',L,R+1,total);
}
vector<string> generateParenthesis(int n) {
if(n==0)return ans;
dfs("(",1,0,2*n);
return ans;
}
};

全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]

输出:

[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

思路

dfs,用一个数组记录下已经访问过的元素即可

该方法对于有重复元素也有效

代码

class Solution {
public:
void dfs(int step,vector<int>cur,vector<int>&nums,int*vis,vector<vector<int>>&ans){
if(step>nums.size())return;
if(step==nums.size()){
ans.push_back(cur);
return;
}
for(int i=0;i<nums.size();++i){
if(!vis[i]){
vis[i]=1;
cur.push_back(nums[i]);
dfs(step+1,cur,nums,vis,ans);
vis[i]=0;
cur.pop_back();
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> ans;
if(nums.size()==0)return ans;
int vis[nums.size()];
memset(vis,0,sizeof(vis));
vector<int>tmp;
dfs(0,tmp,nums,vis,ans);
return ans;
}
};

子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]

输出:

[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

思路

跟全排列很相似,但是不能重复([1,2]和[2,1]是相同的子集)

所以搜索的范围限制在left之后,即只会从大往小([1,2],[1,3],[2,3])

这样就不会重复了

代码

class Solution {
public:
void dfs(int step, vector<int> cur,int left,int*vis, int limit,const vector<int>&nums, vector<vector<int>>&ans){
if(step>limit)return;
if(step==limit){
ans.push_back(cur);
return;
}
for(int i=left;i<nums.size();++i){
if(!vis[i]){
vis[i]=1;
cur.push_back(nums[i]);
dfs(step+1,cur,i+1,vis,limit,nums,ans);
cur.pop_back();
vis[i]=0;
}
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> ans;
vector<int>emp;
ans.push_back(emp);
int vis[nums.size()];
if(nums.size()==0)return ans;
for(int i=1;i<=nums.size();++i){
memset(vis,0,sizeof(vis));
dfs(0,emp,0,vis,i,nums,ans);
}
return ans;
}
};

单词搜索

给定一个二维网格和一个单词,找出该单词是否存在于网格中。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例:

board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
] 给定 word = "ABCCED", 返回 true.
给定 word = "SEE", 返回 true.
给定 word = "ABCB", 返回 false.

思路

首先是不能回头,那么每次dfs将当前的位置标记(可以使用标志数组)

这里我直接将board赋值为' ',注意dfs完恢复原来的值

每一步判断越界和比较当前位置的字符是否等于word对应位置的字符

找到之后将全局flag设为true,防止做无用功

代码

class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
this->board=board;
this->word=word;
this->mx=board.size();
this->my=board[0].size();
this->find=false;
for(int i=0;i<mx;++i){
for(int j=0;j<my;++j){
if(dfs(i,j,0))return true;
}
}
return false;
}
private:
bool dfs(int x,int y, int cur){
if(cur==this->word.size()){
this->find=true;
return true;
}
if(x<0||x>=this->mx||y<0||y>=this->my||this->board[x][y]!=this->word[cur]){
return false;
}
if(find){
return true;
}
char tmp=board[x][y];
board[x][y]=' ';
if(dfs(x-1,y,cur+1)||dfs(x,y-1,cur+1)||dfs(x,y+1,cur+1)||dfs(x+1,y,cur+1)){
find=true;
board[x][y]=tmp;
return true;
}
board[x][y]=tmp;
return false;
}
vector<vector<char>>board;
string word;
int mx,my;
bool find;
};

leetcode回溯算法--基础难度的更多相关文章

  1. LeetCode通关:连刷十四题,回溯算法完全攻略

    刷题路线:https://github.com/youngyangyang04/leetcode-master 大家好,我是被算法题虐到泪流满面的老三,只能靠发发文章给自己打气! 这一节,我们来看看回 ...

  2. LeetCode:回溯算法

    回溯算法 这部分主要是学习了 labuladong 公众号中对于回溯算法的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 总结 概述 回溯是 DFS 中的一种技巧.回溯法采用 ...

  3. LeetCode刷题191203 --回溯算法

    虽然不是每天都刷,但还是不想改标题,(手动狗头 题目及解法来自于力扣(LeetCode),传送门. 算法(78): 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明: ...

  4. Leetcode——回溯法常考算法整理

    Leetcode--回溯法常考算法整理 Preface Leetcode--回溯法常考算法整理 Definition Why & When to Use Backtrakcing How to ...

  5. C#LeetCode刷题-回溯算法

    回溯算法篇 # 题名 刷题 通过率 难度 10 正则表达式匹配   18.8% 困难 17 电话号码的字母组合   43.8% 中等 22 括号生成   64.9% 中等 37 解数独   45.8% ...

  6. 回溯算法 LEETCODE别人的小结 一八皇后问题

    回溯算法实际上是一个类似枚举的搜索尝试过程,主要是在搜索尝试中寻找问题的解,当发现已不满足求解条件时,就回溯返回,尝试别的路径. 回溯法是一种选优搜索法,按选优条件向前搜索,以达到目的.但是当探索到某 ...

  7. LeetCode37 使用回溯算法实现解数独,详解剪枝优化

    本文始发于个人公众号:TechFlow,原创不易,求个关注 数独是一个老少咸宜的益智游戏,一直有很多拥趸.但是有没有想过,数独游戏是怎么创造出来的呢?当然我们可以每一关都人工设置,但是显然这工作量非常 ...

  8. Java求解迷宫问题:栈与回溯算法

    摘要: 使用栈的数据结构及相应的回溯算法实现迷宫创建及求解,带点JavaGUI 的基础知识. 难度: 中级 迷宫问题是栈的典型应用,栈通常也与回溯算法连用. 回溯算法的基本描述是: (1)  选择一个 ...

  9. Gray Code——陈瑶师姐面试时候要用回溯算法

    The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...

随机推荐

  1. C语言搬书学习第一记 —— 认识一个简单程序的细节

    #include<stdio.h> /*告诉编译器把stdio.h 中的内容包含在当前程序中,stdio.h是C编译器软件包的标准部分,它提供键盘输入和 屏幕输入的支持studio.h文件 ...

  2. Feign Date类型时间错误问题

    问题 在feign传输date类型的数据时,在调用方时间正确,而被调用方获取时时间会相差14个小时. 原因 Feign客户端在进行通信时,会将Date类型对象转为String类型,如果这个时间是北京时 ...

  3. Database mirroring connection error 4 'An error occurred while receiving data: '10054(An existing connection was forcibly closed by the remote host.)

    公司一SQL Server镜像发生了故障转移(主备切换),检查SQL Server镜像发生主备切换的原因,在错误日志中发现下面错误: Date        2019/8/31 14:09:17   ...

  4. 以太网驱动的流程浅析(三)-ifconfig的-19错误最底层分析【原创】

    以太网驱动流程浅析(三)-ifconfig的-19错误最底层分析 Author:张昺华 Email:920052390@qq.com Time:2019年3月23日星期六 此文也在我的个人公众号以及& ...

  5. JVM-7-类加载机制

    什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构. ...

  6. vue-property-decorator和typescript结合构建的class类组件,父组件触发子组件方法的方式

    vue-property-decorator和typescript结合构建的class类组件,父组件触发子组件方法的方式 class类组件示例 Father类组件 <template> & ...

  7. PHP 管理树莓派

    同学给过我一块树莓派,那会儿觉得挺新鲜的.但是每次使用都需要远程桌面或者 ssh 进行登录,比较麻烦.后来为了方便管理,在树莓派上安装部署了 LAMP 环境,然后写了一个简单的 PHP 页面,代码如下 ...

  8. 解决python安装第三方库超时问题

    这里说明一下,配置文件中的url还可以换成下面的URL 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.u ...

  9. 多线程八 Lock

    前面我们可以使用synchronized关键字来实现线程之间的同步互斥,lock接口同样也是在JDK1.5中提出,同样是解决线程安全性问题的另一种解决方案,而且它更强大,更灵活本片博客介绍对其展开介绍 ...

  10. [问题排查]通过调度系统远程执行脚本,报mysql command not found异常

    今天在公司使用LS调度系统(百度内部的工具),执行远程脚本的时候,每次都失败. 脚本内容比较简单,其实就是将HDFS(AFS)中的数据插入到Palo(Doris)数据库中,脚本如下: mysql -h ...