【c/c++算法刷题笔记】—— LeetCode打卡03

【前言】打卡活动,白嫖讲解(b站搜大雪菜),oj用的LeetCode和AcWing 。一天5题,打卡二十一天。

【DFS+回溯】

深度搜索只是一种算法思想,不等同于递归,实现方式即可用递归也可用迭代

1 电话号码的字母组合

题目描述

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

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

样例

输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].

笔记
  1. for(auto u:digits) 这样的循环形式更简便,不用考虑下标等问题,不易出错
		for(int i=0;i<digits.size();i++){ //等价于for(auto u:digits)
            vector<string> now;
            int u=digits[i]-'2';
            for(int j=0;j<chars[u].size();j++){//等价于for(auto c:chars[u-'2']
                char c=chars[u][j];
                for(auto s:state) now.push_back(s+c);
            }
            state=now;
        }
  1. 注意,有时候枚举比找映射规律更方便
  2. vector初始化:vector<int> v(10,1); 数组 v 初始化10个大小,每个值置1
代码
//1 判断边界 2 数据结构 枚举数组 3循环三层 
class Solution {
public:
    string chars[8]={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    vector<string> letterCombinations(string digits) {
        if(digits.empty()) return vector<string>();
        vector<string> state(1,"");//定义了1个string元素的向量,且给出每个元素的初值为""
        for(int i=0;i<digits.size();i++){
            vector<string> now;
            int u=digits[i]-'2';
            for(int j=0;j<chars[u].size();j++){
                char c=chars[u][j];
                for(auto s:state) now.push_back(s+c);
            }
            state=now;
        }
        return state;
    }
};

2 单词搜索

题目描述

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

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

样例

board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]

给定 word = “ABCCED”, 返回 true.
给定 word = “SEE”, 返回 true.
给定 word = “ABCB”, 返回 false.

笔记
  1. DFS 棋盘模板:
int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1}; //上左下右4个方向移动,走过的不能回退,体现在 used[] 上,走过的置1
bool dfs(vector<vector<char>>& board, string& word,int x,int y,int count){
	//出口 1 不满足条件无需进入函数
	if(board[x][y] != word[count]) return false;
	
	//出口 2 满足条件,按题目要求返回结果
	if(count == word.size()-1) return true;
	
	//入口
	board[x][y]='.'; //直接在代替used[]
	for(int i=0;i<4;i++){
		int a=x+dx[i],b=y+dy[i];
		if(a>=0 && a<row && b>=0 && b<col)
			if(dfs(board,word,a,b,count+1)) return true;
	}
	board[x][y]=word[count]; //回溯
	return false;
代码
/*
    1 数据结构  
    2 算法逻辑 
        只有三种走法,不能回退
    
*/ 
class Solution {
public:
    int r,c; //行 列
    int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
    bool exist(vector<vector<char>>& board, string word) {
        if(board.empty()||board[0].empty()) return false;
        r=board.size(), c=board[0].size();
        for(int i=0;i<r;i++){
            for(int j=0;j<c;j++)
                if(dfs(board,word,i,j,0)) return true;
        } 
        return false;
    }
    //传参& 不需要复制数组,如果不加&,复制浪费时间
    bool dfs(vector<vector<char>>& board, string& word,int x,int y,int count){
        if(board[x][y]!=word[count]) return false;
        if(count==word.size()-1) return true; 
        board[x][y]='.';
        for(int i=0;i<4;i++){
            int a=x+dx[i],b=y+dy[i];
            if(a>=0&&a<r&&b>=0&&b<c) 
                if(dfs(board,word,a,b,count+1)) return true;
        }
        //恢复
        board[x][y]=word[count];
       return false;
    }
};

3 全排列

题目描述

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

样例

输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

笔记
  1. 全排列属于递归树里面最基础的题。对题目给定vector数组 操作不熟练。

  2. vector<int> abc; //初始化一个size为0的vector
    vector<int> abc(10); //初始化了10个默认值为0的元素
    vector<int> cde(10,1); //初始化了10个值为1的元素
    int a[5] = {1,2,3,4,5}; vector<int> b(a, a+5); //地址是从0到5(左闭右开区间)
    vector<int> a(5,1); vector<int> b(a);

  3. path.pop_back(); // 弹出

代码
class Solution {
public:
//递归树
int n;
vector<bool> used;
vector<vector<int>> ans;
vector<int> path;

void dfs(vector<int>& nums,int count){
    if(count==n) {
        ans.push_back(path);
        return;
    }
    for(int i=0;i<n;i++){
        if(used[i]==0){
            used[i]=1;
            path.push_back(nums[i]);
            dfs(nums,count+1);  
            path.pop_back();  //恢复现场
            used[i]=0;
        }
    }
}
    vector<vector<int>> permute(vector<int>& nums) {
        n=nums.size();  //保存大小 方便使用
        used = vector<bool>(n); //vector 赋值
        dfs(nums,0);   
        return ans;
    }
};

4 全排列(含重复数字)

题目描述

给定一个可包含重复数字的序列,返回所有不重复的全排列。

样例

输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

笔记
  1. 含重复数字关键是要把相同数字产生的相同排列跳过——判重。先把所有相同数字放到一起,便于跳过,给dfs加一个参数 start,若后一个数相同,则从下一个位置开始遍历。如 1->5,第二个 1 只能从 位置6 开始 。为了实现 在基础模板上 增加了 sort函数,start参数
  2. 此题解法为:枚举每个数放到哪个位置,上题:枚举每个位置放哪个数。两种方法均可。
    其中,枚举每个数放到哪个位置:path [i]=nums [count];
    枚举每个位置放哪个数:path [count] = nums [i]; count表示“每个”
代码
class Solution {
public:
    int n;
    vector<int> used;
    vector<int> path;
    vector<vector<int>> ans;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        n=nums.size();
        used=vector<int>(n);
        path=vector<int>(n);
        sort(nums.begin(),nums.end());
        dfs(nums,0,0);
        return ans;
    }
    void dfs(vector<int>& nums,int count,int start){
        if(count==n){
            ans.push_back(path); 
            return;
        }
        for(int i=start;i<n;i++){
            if(used[i]==0){
                used[i]=1;
                path[i]=nums[count];    //与之前不同
                int sta = count+1<n && nums[count+1]==nums[count]?i+1:0;
                dfs(nums,count+1,sta);
                used[i]=0;
            }
        }
    }
};

5 子集

题目描述

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

样例

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

笔记

集合问题中,利用 二进制 进行移位运算是最简便的方法,例中,元素个数 为 3 ,幂集个数为 23,循环 0-8 ,用二进制表示,每位与1判断此位是否为1,若为1,输出此下标元素

代码
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> ans;
        for(int i=0;i< 1<<nums.size();i++){
            vector<int> temp;
            for(int j=0;j<nums.size();j++){
                if(i>>j & 1) temp.push_back(nums[j]);
            }
            ans.push_back(temp);
        }
        return ans;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值