TOP100-回溯(二)

4.39. 组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:

输入:candidates =[2,3,6,7],target =7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

示例 2:

输入: candidates = [2,3,5],target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入: candidates =[2],target = 1
输出: []

提示:

  • 1 <= candidates.length <= 30
  • 2 <= candidates[i] <= 40
  • candidates 的所有元素 互不相同
  • 1 <= target <= 40

思路:

本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回!

代码:

// 剪枝优化
class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(candidates); // 先进行排序
        backtracking(res, new ArrayList<>(), candidates, target, 0, 0);
        return res;
    }

    public void backtracking(List<List<Integer>> res, List<Integer> path, int[] candidates, int target, int sum, int idx) {
        // 找到了数字和为 target 的组合
        if (sum == target) {
            res.add(new ArrayList<>(path));
            return;
        }

        for (int i = idx; i < candidates.length; i++) {
            // 如果 sum + candidates[i] > target 就终止遍历
            if (sum + candidates[i] > target) break;
            path.add(candidates[i]);
            backtracking(res, path, candidates, target, sum + candidates[i], i);
            path.remove(path.size() - 1); // 回溯,移除路径 path 最后一个元素
        }
    }
}

Python: 

class Solution:

    def backtracking(self, candidates, target, total, startIndex, path, result):
        if total == target:
            result.append(path[:])
            return

        for i in range(startIndex, len(candidates)):
            if total + candidates[i] > target:
                continue
            total += candidates[i]
            path.append(candidates[i])
            self.backtracking(candidates, target, total, i, path, result)
            total -= candidates[i]
            path.pop()

    def combinationSum(self, candidates, target):
        result = []
        candidates.sort()  # 需要排序
        self.backtracking(candidates, target, 0, 0, [], result)
        return result

5.22. 括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

提示:

  • 1 <= n <= 8

思路:

回溯法,想象是否成功,通通建立2*n高的树,设置左右标志;加入左括号,则左标志+1,加入右括号,则右标志+1;仅当到达叶子节点时,左右标志也为n,才算做正确的输出。

代码:

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        if n<=0:return []
        res = []

        def dfs(paths,left,right):
            if left>n or right >left: return#左括号多了,和右括号大于左括号数时,直接拜拜
            if len(paths) == n*2:
                res.append(paths)
                return

            dfs(paths+'(',left+1,right)
            dfs(paths+')',left,right+1)
        
        dfs('',0,0)
        return res

6.79. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

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

示例 1:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

示例 2:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true

示例 3:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false

提示:

  • m == board.length
  • n = board[i].length
  • 1 <= m, n <= 6
  • 1 <= word.length <= 15
  • board 和 word 仅由大小写英文字母组成

思路:

思路也应该就是深度优先搜索,然后剪枝。关键点在于:当访问到的位置不是下一个预期值时,直接跳出,然后回溯,不继续下去。

代码:

class Solution {
    public int m;
    public int n;
    public boolean exist(char[][] board, String word) {
        m=board.length;
        n=board[0].length;
        char[] words=word.toCharArray();
        for(int i =0;i<m;i++){
            for(int j = 0;j<n;j++){
                if(dfs(board,words,i,j,0))return true;
            }
        }
        return false;
    }
    boolean dfs(char[][] board,char[] word,int i,int j,int k){
        if(i>=m || i<0 || j>=n || j<0 || board[i][j] != word[k])return false;
        if(k == word.length-1)return true;
        board[i][j]='\0';
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = word[k];
        return res;
    }
}

7.131. 分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串。返回 s 所有可能的分割方案。

示例 1:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

示例 2:

输入:s = "a"
输出:[["a"]]

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

思路:

1.先写一个函数用于判断是否为回文串
2.要划分出所有的子串,就是通过构建树来完成,而这个过程会用到深度优先搜索dfs(i)这个i是指第i个以后还没有遍历处理,而不是对第i个做操作,子串操作s.substring(start,end+1)
其他内容详见

代码:

class Solution {
    private String s;
    private final List<List<String>> res = new ArrayList<>();
    private final List<String> path = new ArrayList<>();//路径变量
    public List<List<String>> partition(String s) {
        this.s=s;//首先给字符串赋值
        //开始回溯(递归寻找)
        dfs(0,0);
        return res; 
    }

    private boolean isHuiWen(int left, int right){
        while(left<right)
            if(s.charAt(left++)!=s.charAt(right--))
                return false;
        return true;
    }

    //i后面的还没处理,从Start开始
    private void dfs(int i, int  start){
        if(i==s.length()){
            res.add(new ArrayList<>(path));//说明这个已经完成了,复制
            return;
        }
        //不选i与i+1之间的逗号
        if(i < s.length() - 1)
            dfs(i+1,start);
        // 选 i 和 i+1 之间的逗号(把 s[i] 作为子串的最后一个字符)
        //要对于检查回文的部分做操作,也就是把s[i]作为字符串的最后一个字符,
        //需要判断从start到i
        if(isHuiWen(start,i)){
            path.add(s.substring(start,i+1));//切割子串,第i+1不算入
            //判断下一个字符作为头
            dfs(i+1,i+1);
            path.remove(path.size()-1);//恢复现场
        }
    }


}

8.51. N 皇后

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例 1:

输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:[["Q"]]

提示:

  • 1 <= n <= 9

思路:

首先,抄来回溯的模板:

void backtracking(参数){
    if(终止条件){
        存结果;
        return;        
    }
    for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)){
        处理节点;
        backtracking(路径,选择列表);//递归
        回溯,撤销处理结果;
    }

}

 递归函数参数:

依然是定义全局变量二维数组result来记录最终的结果。

参数n是棋盘的大小,然后用row来记录当前遍历到了棋盘的第几层

这部分代码是:

result=[[]*n]*n
def backtrak(n , row , chessboard):#chessboard为棋盘
    

我们是逐行去寻找的,因此可以想到当当前遍历行数row为第n行时,回溯到了终点。因此回溯终点为:

if row == n :
    result.push_back(chessboard)
    return

单层搜索的逻辑:

递归深度其实就是row控制棋盘的行,每一层里for循环的col控制棋盘的列,一行一列决定了皇后的位置。
每次都是从新的一行开始搜索,因此都是从0开始

代码如下:

for(int col = 0; col < n ; col++){
    if(isValid(row,col,chessboard,n))
        chessboard[row][col] = 'Q';
        backtrack(n,row+1,chessboard);
        chessboard[row][col] = '.';    
}

验证是否合法的逻辑是:

1.不能同行
2.不能同列
3.不能同斜线(45度和135度)

代码:

bool isVaild(int row,int col, vector<string>& chessboard , int n){
    for(int i= 0;i < row ; i++){//同一列
        if(chessboard[i][col]=='Q')return false;
    }
    //45度检查
    for(int i= row-1 ,int j =col-1;i >=0 && j >=0 ; i--,j--){
        if(chessboard[i][j]=='Q')return false;    
    }
    //135度检查
    for(int i= row-1 ,int j =col+1;i >=0 && j < n  ; i--,j++){
        if(chessboard[i][j]=='Q')return false;  
    }
    return true;

}

 总结来说:

棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度,这样就可以套进回溯法的模板里了

代码:

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        result = []  # 存储最终结果的二维字符串数组

        chessboard = ['.' * n for _ in range(n)]  # 初始化棋盘
        self.backtracking(n, 0, chessboard, result)  # 回溯求解
        return [[''.join(row) for row in solution] for solution in result]  # 返回结果集

    def backtracking(self, n: int, row: int, chessboard: List[str], result: List[List[str]]) -> None:
        if row == n:
            result.append(chessboard[:])  # 棋盘填满,将当前解加入结果集
            return

        for col in range(n):
            if self.isValid(row, col, chessboard):
                chessboard[row] = chessboard[row][:col] + 'Q' + chessboard[row][col+1:]  # 放置皇后
                self.backtracking(n, row + 1, chessboard, result)  # 递归到下一行
                chessboard[row] = chessboard[row][:col] + '.' + chessboard[row][col+1:]  # 回溯,撤销当前位置的皇后

    def isValid(self, row: int, col: int, chessboard: List[str]) -> bool:
        # 检查列
        for i in range(row):
            if chessboard[i][col] == 'Q':
                return False  # 当前列已经存在皇后,不合法

        # 检查 45 度角是否有皇后
        i, j = row - 1, col - 1
        while i >= 0 and j >= 0:
            if chessboard[i][j] == 'Q':
                return False  # 左上方向已经存在皇后,不合法
            i -= 1
            j -= 1

        # 检查 135 度角是否有皇后
        i, j = row - 1, col + 1
        while i >= 0 and j < len(chessboard):
            if chessboard[i][j] == 'Q':
                return False  # 右上方向已经存在皇后,不合法
            i -= 1
            j += 1

        return True  # 当前位置合法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/496999.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows安装jdk8

我们会在windows中通过Java代码去操作hadoop集群&#xff0c;因此我们需要在windows系统中配置java相关的环境&#xff0c;今天带着大家安装以下jdk8. 1.找到jdk8的安装文件 2.双击该文件进行安装 稍微等待一会儿&#xff08;30秒左右&#xff0c;有时时间会长些&#xff09; 安…

代码随想录第23天| 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 669. 修剪二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 你修剪的方式不对&#xff0c;我来给你纠正一下&#xff01;| LeetCode&#xff1a;669. 修剪二叉搜索树_哔哩哔哩_bilibili 给你二叉搜索树的根节点 root …

学点儿Java_Day12_IO流

1 IO介绍以及分类 IO: Input Output 流是一组有顺序的&#xff0c;有起点和终点的字节集合&#xff0c;是对数据传输的总称或抽象。即数据在两设备间的传输称为流&#xff0c;流的本质是数据传输&#xff0c;根据数据传输特性将流抽象为各种类&#xff0c;方便更直观的进行数据…

【I.MX6ULL移植】Ubuntu-base根文件系统移植

1.下载Ubuntu16.04根文件系统 http://cdimage.ubuntu.com/ 1 2 3 4 5 2.解压ubuntu base 根文件系统 为了存放 ubuntu base 根文件系统&#xff0c;先在 PC 的 Ubuntu 系统中的 nfs 目录下创建一个名为 ubuntu_rootfs 的目录&#xff0c;命令如下&#xff1a; 【注意&…

librdkafka的简单使用

文章目录 摘要kafka是什么安装环境librdkafka的简单使用生产者消费者 摘要 本文是Getting Started with Apache Kafka and C/C的中文版&#xff0c; kafka的hello world程序。 本文完整代码见仓库&#xff0c;这里只列出producer/consumer的代码 kafka是什么 本节来源&#…

C# 高级文件操作与异步编程探索(初步)

文章目录 文本文件的读写探秘StreamReader 类深度剖析StreamWriter 类细节解读编码和中文乱码的解决方案 二进制文件的读写BinaryReader 类全面解析BinaryWriter 类深度探讨 异步编程与C#的未来方向同步与异步&#xff1a;本质解读Task 的神奇所在async/await 的魔法 在现代编程…

NOIP,CSP-J,CSP-S——树

一、树 概念: 节点、深度、路径、边 树的直径 真题: 答案:B 答案:A 一个树的边是n-1 现在是m,所以m-(n-1)=m-n+1

Elasticsearch 向量搜索

目标记录 ["你好&#xff0c;我的爱人","你好&#xff0c;我的爱妻","你好&#xff0c;我的病人","世界真美丽"] 搜索词 爱人 预期返回 ["你好&#xff0c;我的爱人","你好&#xff0c;我的爱妻"] 示例代码…

解决 vue activited 无效问题

当对页面APP.vue组件router-view标签使用了keep-alive之后在组件activated状态时不会发送请求&#xff0c;这时需要使用 keep-alive标签的 exclude属性排除需要重新发送请求的组件。需要注意exclude的值要和组件本身的name值要一致&#xff0c;如果不一致就会不生效。目前我出现…

element-ui checkbox 组件源码分享

简单分享 checkbox 组件&#xff0c;主要从以下三个方面来分享&#xff1a; 1、组件的页面结构 2、组件的属性 3、组件的方法 一、组件的页面结构 二、组件的属性 2.1 value / v-model 属性&#xff0c;绑定的值&#xff0c;类型 string / number / boolean&#xff0c;无…

46.continue语句

目录 一.continue语句 二.视频教程 一.continue语句 continue语句的作用和break语句很像&#xff0c;break语句会跳出当前循环&#xff0c;而continue语句则是跳出本次循环&#xff0c;继续执行下一次循环。 举个例子&#xff1a; #include <stdio.h>void main(void)…

想学网络安全,从哪里开始?网络安全的学习路线

网络安全学习路线&#xff1a; 想学习网络安全专业的知识&#xff0c;想当黑客&#xff0c;但是不知道该从哪里开始学。 我给你一个路线&#xff01; 清晰图片和大纲&#xff1a;https://docs.qq.com/doc/DU1lpVFpSbWVrd2p3

【每周精选资讯 | 第 1 期】2024-03-11 ~ 2024-03-17

前言 大家好&#xff0c;我是翼同学。这里是【每周精选资讯】的第一期内容。 GPT 递给我苹果 Figure展示了与OpenAI合作的最新进展&#xff0c;通过结合先进的神经网络&#xff0c;使机器人能够执行类似人类的快速、灵巧动作。主要功能包括描述周围环境、常识推理、将高层次…

Android ImageView以及实现截图

实现效果 截图前 截图后 代码 package cn.jj.huaweiad;import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.ViewGro…

螺旋矩阵的算法刷题

螺旋矩阵的算法刷题 本文主要涉及螺旋矩阵的算法 包括三个题目分别是 59. 螺旋矩阵 II54. 螺旋矩阵 中等LCR 146. 螺旋遍历二维数组 文章目录 螺旋矩阵的算法刷题一 、螺旋矩阵简单1.1 实现一&#xff08;我认为这个方法更巧妙&#xff01;&#xff01;&#xff09;1.2 实现二&…

Redis入门到实战-第十七弹

Redis实战热身t-digest篇 完整命令参考官网 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#xff09;&#xff0c;用作数据库、缓存、消息代理…

2024最新华为OD机试试题库全 -【二叉树计算】- C卷

1. 🌈题目详情 1.1 ⚠️题目 给出一个二叉树如下图所示: 请由该二叉树生成一个新的二叉树,它满足其树中的每个节点将包含原始树中的左子树和右子树的和。 左子树表示该节点左侧叶子节点为根节点的一颗新树;右子树表示该节点右侧叶子节点为根节点的一颗新树。 1.2 �…

自养号测评,补单的五大关键要素

现在很多大卖都是自己管理几百个账号&#xff0c;交给服务商不是特别靠谱 第一 你不知道服务商账号质量怎么样 第二 账号一天下了多少你也不清楚&#xff0c;如果下了很多单万一封号被关联了怎么办 第三 你也不知道服务商用什么卡给你下单&#xff0c;用一些低汇率和黑卡下单…

运用开关量信号远程传输装置实现工厂智能化技改需要分几步走

DTD509H系列开关量信号无线传输器由一个无线信号发射终端和一个无线信号接收终端组成&#xff0c;也可以根据用户现场实现一点对多点或者多点对一点的无线控制。DTD509H系列开关量信号无线传输器可与PLC的IO端口、继电器、二次仪表、传感器等工业设备配套使用&#xff0c;运用无…

【前端Vue】社交信息头条项目完整笔记第2篇:二、登录注册,准备【附代码文档】

社交媒体-信息头条项目完整开发笔记完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;一、项目初始化使用 Vue CLI 创建项目,加入 Git 版本管理,调整初始目录结构,导入图标素材,引入 Vant 组件库,移动端 REM 适配,关于 , 配置文件,封装请求模块。十、用户关…