【算法/题目】:递归、搜索训练

news2024/11/14 21:49:49

✨                                                 吾与春风皆过客,君携春水揽星河         🌏 

📃个人主页:island1314

🔥个人专栏:算法训练

🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏  💞 💞 💞


1. 找出所有子集的异或总和再求和

思路:

        假设存在[1,2,3]这个集合,那么开始的时候是空集合,画出其决策树

全局变量:sum和path

sum用于求异或和,path用来当进入某一层时,异或该数,

方法dfs : dfs(nums[],pos) 在pos那层

回溯:异或运算:消消乐(相同的数异或为0)

AC代码如下:

int path, sum;
void dfs(vector<int>& nums, int pos)
{
	sum += path;
	for (int i = pos; i < nums.size(); i++)
	{
		path ^= nums[i];
		dfs(nums, i + 1);
		path ^= nums[i]; //恢复现场
	}
}
int subsetXORSum(vector<int>& nums) {
	dfs(nums, 0);
	return sum;
}

2.  N皇后

思路:

深度优先遍历(DFS)

函数名:void dfs(int r): 深度优先遍历函数。参数r:从第r行开始放棋子,处理第r行。

递归结束判定:见代码,当 r == n的时候,说明应该处理第 n行了,也代表第 0~n-1行放好棋子,也就是整个棋盘放好了棋子,也就是得到了一种解,也就是递归结束。

第r行,第i列能不能放棋子:数组dg udl 分别表示:点对应的两个斜线以及列上是否有皇后。
dg[x + y] 表示 y行x列处,所在的对角线上有没有棋子,udg[n - x + y]表示 r行i列处,所在的反对角线上有没有棋子,cor[i]表示第i列上有没有棋子。如果 y行x列的对角线,反对角线上都没有棋子,即!col[x] && !dg[i + r] && !udg[n - i + r]为真,则代表 x行y列处可以放棋子。

AC代码如下:

vector<vector<string>> ret;
vector<string> path;
bool col[20], udg[20], dg[20];
int n;

void dfs(int pos) {
    if (pos == n) {
        ret.push_back(path);
        return;
    }
    int x = pos;
    for (int y = 0; y < n; y++) { // 尝试在这一行放皇后
        if (!col[y] && !dg[y - x + n] && !udg[y + x]) {
            col[y] = dg[y - x + n] = udg[y + x] = true;
            path[x][y] = 'Q';

            dfs(x + 1);
            path[x][y] = '.';
            col[y] = dg[y - x + n] = udg[y + x] = false;
        }
    }
}

vector<vector<string>> solveNQueens(int _n) {
    n = _n;
    path.resize(n);
    for (int i = 0; i < n; i++) {
        path[i].append(n, '.');
    }
    dfs(0);
    return ret;
}
   

3. 有效的数独

 

思路:

创建二维数组 rows 和 col 分别记录数独的每一行和每一列中的每个数字的出现次数

创建三维数组 grid 记录数独的每一个小九宫格中的每个数字的出现次数

        其中rows[i][num]、columns[j][num] 和 gird[i / 3] [j / 3][num] 分别表示数独的第 i 行第 j 列的单元格所在的行、列和小九宫格中,数字 num + 1 出现的次数,其中 0≤ num <9,对应的数字 num+1 满足 1≤num+1≤9。

AC代码如下:

bool col[9][10], row[9][10];
bool grid[3][3][10];
bool isValidSudoku(vector<vector<char>>& board) {
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (board[i][j] != '.') {
				int num = board[i][j] - '0';
				if (row[i][num] || col[j][num] || grid[i / 3][j / 3][num])
					return false;
				row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = true;
			}
		}
	}
	return true;
}

4、解数独

思路:

和上题类似的是,我们同样用

   创建二维数组 rows 和 col 分别记录数独的每一行和每一列中的每个数字的出现次数

   创建三维数组 grid 记录数独的每一个小九宫格中的每个数字的出现次数

我们首先对整个数独数组进行遍历,当我们遍历到第 i 行第 j 列的位置:

  • 如果该位置是一个空白格,那么我们将其加入一个用来存储空白格位置的列表中,方便后续的递归操作;

  • 如果该位置是一个数字 num,那么我们需要将 row[ i ][ num ],col[ j ][num以及 block[ ⌊i/3⌋ ][ ⌊j/3⌋ ][num] 均置为 True。

当我们结束了遍历过程之后,就可以开始递归枚举。当递归到第 i 行第 j 列的位置时,我们枚举填入的数字 num。根据题目的要求,数字 num 不能和当前行、列、九宫格中已经填入的数字相同,因此 row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = false;

当我们填入了数字 num 之后,我们要将上述的三个值都置为 True,并且继续对下一个空白格位置进行递归。在回溯到当前递归层时,我们还要将上述的三个值重新置为 False。

AC代码如下:

bool row[9][10], col[9][10];//储存每一行每一列存在的数字 
bool grid[3][3][10]; //储存每一个 3*3宫存在的数字

bool dfs(vector<vector<char>>& board) {
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (board[i][j] == '.') {
				//填数
				for (int num = 1; num <= 9; num++) {
					if (!row[i][num] && !col[j][num] && !grid[i / 3][j / 3][num]) {
						board[i][j] = '0' + num;
						row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = true;
						if (dfs(board) == true) return true;

						//恢复现场
						board[i][j] = '.';
						row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = false;
					}
				}
				// 当前格子 1- 9 都不能填,那么就只能返回到上一个格子进行修改
				return false;
			}
		}
	}
	return true;
}

void solveSudoku(vector<vector<char>>& board) {
	//初始化
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (board[i][j] != '.') {
				int num = board[i][j] - '0';
				row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = true;
			}
		}
	}
	dfs(board);
}

5、单词搜索

思路:

设函数 dfs(board,words,x,y,pos) 表示判断以网格的 (x,y)位置出发,能否搜索到单词 words[pos..],其中 words[pos..] 表示字符串 word 从第 pos 个字符开始的后缀子串。如果能搜索到,则返回 true,反之返回 false。函数 dfs(board,words,x,y,pos)的执行步骤如下:

  • 如果 board[ x ][ y ] = words[pos],当前字符不匹配,直接返回 false。
  • 如果当前已经访问到字符串的末尾,且对应字符依然匹配,此时直接返回 true。
  • 否则,遍历当前位置的所有相邻位置。如果从某个相邻位置出发,能够搜索到子串 word[pos+1..],则返回 true,否则返回 false。

这样,我们对每一个位置 (x,y)都调用函数 dfs(board,words,x,y,pos)进行检查:只要有一处返回 true,就说明网格中能够找到相应的单词,否则说明不能找到。

为了防止重复遍历相同的位置,需要额外维护一个与 board 等大的 st 数组,用于标识每个位置是否被访问过。每次遍历相邻位置时,需要跳过已经被访问的位置。

注意:

if (dfs(board, word, i, j, 0)) return true;,而不是return dfs(board, word, i, j, 0);

AC代码如下:

int dir[4][2] = {
		{1,0},{0,1},{-1,0},{0,-1}
};
int n, m;
bool st[505][505];

bool dfs(vector<vector<char>>& board, string word, int x, int y, int pos) {
	if (pos == word.size()) return true;
	//向量的方式,定义上下左右四个位置

	for (int i = 0; i < 4; i++) {
		int dx = x + dir[i][0], dy = y + dir[i][1];
		if (dx >= 0 && dx < n && dy >= 0 && dy < m && board[dx][dy] == word[pos] && !st[dx][dy]) {
			st[dx][dy] = true;
			if (dfs(board, word, dx, dy, pos + 1)) return true;
			st[dx][dy] = false;
		}
	}
	return false;
}

bool exist(vector<vector<char>>& board, string word) {
	n = board.size(), m = board[0].size();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (board[i][j] == word[0]) {
				st[i][j] = true;
				if (dfs(board, word, i, j, 1)) return true;
				st[i][j] = false;
			}
		}
	}
	return false;
}

6、黄金矿工

思路:

该题与上题解题步骤基本类似,只不过该题需要多加一个参数sum,来记录每条的和,然后求出最大值即可。

AC代码如下:

int dir[4][2] = {
    {1,0},{0,1},{-1,0},{0,-1}
};
int maxi = 0;
int n, m;
bool st[505][505];

void dfs(vector<vector<int>>& grid, int x, int y, int sum) {
    maxi = max(maxi, sum);
    for (int i = 0; i < 4; i++) {
        int dx = x + dir[i][0], dy = y + dir[i][1];
        if (dx >= 0 && dx < n && dy >= 0 && dy < m && grid[dx][dy] > 0 && !st[dx][dy]) {
            st[dx][dy] = true;
            dfs(grid, dx, dy, sum + grid[dx][dy]);
            st[dx][dy] = false;

        }
    }
}

int getMaximumGold(vector<vector<int>>& grid) {
    n = grid.size(), m = grid[0].size();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] != 0) {
                st[i][j] = true;
                dfs(grid, i, j, grid[i][j]);
                st[i][j] = false;
            }
        }
    }
    return maxi;
}

7、不同路径III

思路:

该题我们选择dfs的方法,主要步骤和 5、6题过程类似,但是在进行dfs之前,我们先需要做一些初始化的步骤,比如找到起始位置,和记录应该需要走的总步数

AC代码如下:

bool st[25][25];
int dir[4][2] = {
    {1,0},{0,1},{-1,0},{0,-1}
};
int ret, step; //统计走的方法,和需要走的总步数
int n, m;

void dfs(vector<vector<int>>& grid, int x, int y, int cnt) {
    if (grid[x][y] == 2) { //走到终止位置
        if (cnt == step) ret++; //看是否走完所有路程
        return;
    }
    for (int i = 0; i < 4; i++) {
        int dx = x + dir[i][0], dy = y + dir[i][1];
        if (dx >= 0 && dx < n && dy >= 0 && dy < m && grid[dx][dy] != -1 && !st[dx][dy]) {
            st[dx][dy] = true;
            dfs(grid, dx, dy, cnt + 1);
            st[dx][dy] = false;
        }
    }
}

int uniquePathsIII(vector<vector<int>>& grid) {
    n = grid.size(), m = grid[0].size();
    
    int bx = 0, by = 0; //记录起始位置
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == 0) step++; // 统计需要走的总步数
            else if (grid[i][j] == 1) bx = i, by = j;
        }
    }
    step += 2; //还需要加上起始位置和终止位置走的步数
    st[bx][by] = true;
    dfs(grid, bx, by, 1);
    return ret;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

117页PPT埃森哲-物流行业信息化整体规划方案

一、埃森哲-物流行业信息化整体规划方案 资料下载方式&#xff0c;请看每张图片右下角信息 埃森哲在物流行业信息化整体规划项目中的核心内容&#xff0c;旨在帮助物流企业通过信息技术的应用实现业务流程的优化、运营效率的提升以及市场竞争力的增强。以下是埃森哲在此类项目…

全面掌握 Kubernetes 对象的基本操作:从定义到实践

引言 Kubernetes 是当今最流行的容器编排平台之一&#xff0c;它通过自动化容器化应用的部署、扩展和管理&#xff0c;极大地提升了应用的可用性和可扩展性。在 Kubernetes 系统中&#xff0c;对象是其核心概念之一&#xff0c;是对系统状态的持久化描述。理解 Kubernetes 对象…

日志定向实验

目录 一.实验环境 二.实验一 1.node1主机进入rsyslog.conf文件添加规则 2.重启服务测试 三.实验二 1.node1主机进入rsyslog.conf文件添加规则 2.node1重启服务&#xff0c;清除日志历史记录 2.node2主机重新登录node1 3.node1没有日志记录 4.node1重启httpd 5.node1…

网络基础之(2)初级网络知识

网络基础之(2)初级网络工程师 Author&#xff1a;Once Day Date: 2024年7月29日 漫漫长路&#xff0c;有人对你笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的博客-CSDN博客。 来自锐捷数通技术基础资料&#xff0c;百度云盘链接: 下载链接&#xff0c…

状体管理-装饰器

State 自己的状态 注意:不是状态变量的所有更改都会引起刷新。只有可以被框架观察到的修改才会引起UI刷新。 1、boolean、string、number类型时&#xff0c;可以观察到数值的变化。 2、class或者Object时&#xff0c;可以观察 自身的赋值 的变化&#xff0c;第一层属性赋值的变…

【控制研究领域EI会议推荐】第四届电气工程与控制科学国际学术会议(IC2ECS 2024)

【拟IEEE出版|连续3届稳定EI检索|团队投稿可享优惠】 第四届电气工程与控制科学国际学术会议&#xff08;IC2ECS 2024&#xff09; 2024 4th International Conference on Electrical Engineering and Control Science *拟IEEE 出版&#xff0c;连续3届稳定EI检索&#xff0…

了解三大无线通信技术(Wifi、蓝牙、NFC)

1.WIFI Wi-Fi&#xff08;Wireless Fidelity&#xff09;&#xff0c;又称作“移动热点”&#xff0c;是当今使用最广的一种无线网络传输技术。Wi-Fi技术是把有线网络信号转换成无线信号&#xff0c;形成无线局域网&#xff0c;将局域网内的设备联网。比如我们通过一个无线路由…

【Vue3】组件通信之自定义事件

【Vue3】组件通信之自定义事件 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋…

【重整化群】1.0 to Wilson RG

0. 写在最前面 从高能到统计物理模型RG的技术主要参考 大黄猫的量子多体讲义&#xff0c;杨展如NRG / DMRG 暂时没有想法&#xff0c;编排不出内容有趣的零碎内容&#xff0c;如 CFT&#xff0c;Z2 Lattice gauge, Fermi field 重整化零碎内容&#xff0c;下篇文章将逐一讲述 …

UE5.4内容示例(4)UI_UMG - 学习笔记

https://www.unrealengine.com/marketplace/zh-CN/product/content-examples 《内容示例》是学习UE5的基础示例&#xff0c;可以用此熟悉一遍UE5的功能 UI示例 UI_UMG &#xff1a;基本UMGUI_CommonUI &#xff1a;UMG多层应用UI_SlatePostBuffer UI &#xff1a;FX的示例&…

python中的print函数总结

文章目录 打印变量打印数学计算多行文本复制n次字符串 x*n,n*x不换行输出多个数据换行符制表位转义原字符字符串切片格式化字符串千位分隔符&#xff08;只适用于整数和浮点数&#xff09;浮点数小数部分的精度字符串类型&#xff0c;.表示最大的显示长度整数类型浮点数类型 打…

<Qt> 常用控件

目录 一、控件概述 二、QWidget 核心属性 &#xff08;一&#xff09;QWidget的核心属性概览 1. enabled 2. geometry 3. WindowFrame的影响 4. windowTitle 5. window Icon 6. windowOpacity 7. cursor 8. font 9. toolTip 10. focusPolicy 11. styleSheet 三、…

docker网络介绍net

docker 几种网络模式 bridge模式 使用–netbridge参数指定网络模式&#xff0c;docker的默认模式就是bridge模式&#xff0c;默认选择bridge的情况下&#xff0c;容器启动的时候会通过DHCP获取一个ip地址&#xff0c;这可能不是我们想要的&#xff0c;在centos系统下&#xff…

springboot给类进行赋初值的四种方式

目录 1. 使用Value和ConfigurationProperties2. 使用PropertySource创建Person.java写一个测试类 3. 使用ImportResourceStudent类创建beans.xml在主类中引入测试 心得 1. 使用Value和ConfigurationProperties 这里不加赘述了&#xff0c;前面我也发过&#xff0c;这里就放个链…

redis--分布式锁(1)

分布式锁的基本需求 互斥性&#xff1a;在任何时刻&#xff0c;只有一个客户端能持有锁。无死锁&#xff1a;即使一个客户端在持有锁的期间崩溃&#xff0c;其他客户端也能获得锁。容错性&#xff1a;分布式锁的实现应该能够容忍部分组件的失败&#xff0c;例如&#xff0c;锁服…

Open Interpreter - 开放解释器

文章目录 一、关于演示它是如何工作的&#xff1f;与 ChatGPT 的代码解释器比较 二、快速开始三、更多操作1、互动聊天2、程序化聊天3、开始新的聊天4、保存和恢复聊天5、自定义系统消息6、更改模型7、在本地运行 Open Interpreter终端Python上下文窗口&#xff0c;最大令牌 8、…

JavaScript异步编程的Promise

目录 1.对Promise的了解 &#xff08;1&#xff09;介绍 &#xff08;2&#xff09;Promise 的优缺点 2.Promise的基本用法 &#xff08;1&#xff09;创建Promise对象 &#xff08;2&#xff09;Promise方法then() &#xff08;3&#xff09;Promise方法catch() &…

力扣SQL50 删除重复的电子邮箱 自连接删除 连表删除

Problem: 196. 删除重复的电子邮箱 &#x1f468;‍&#x1f3eb; 参考题解 Code DELETE p1 FROM Person p1,Person p2 WHEREp1.Email p2.Email AND p1.Id > p2.Id

前端Web-JavaScript(下)

主要是补全一下JavaScript 基本对象: String对象 语法格式 方式1&#xff1a; var 变量名 new String("…") ; //方式一 例如&#xff1a; var str new String("Hello String"); 方式2&#xff1a; var 变量名 … ; //方式二 例如&#xff1a; var …

CHCSA第二次作业

#01、创建以上目录和文件结构&#xff0c;并将/yasuo目录拷贝4份到/目录下 [rootlocalhost ~]# ls /yasuo // 先检查是否有yasuo目录 ls: 无法访问 /yasuo: 没有那个文件或目录 [rootlocalhost ~]# mkdir -p /yasuo/dir1 // 递归创建目录 [rootlocalhost ~]#…