数据结构与算法——五个常规算法之三 · 回溯算法
回溯的基本原理
在问题的解空间中,按深度优先遍历策略,从根节点出发搜索解空间树。算法搜索至解空间 的任意一个节点时,先判断该节点是否包含问题的解。如果确定不包含,跳过对以该节点为根的 子树的搜索,逐层向其祖先节点回溯,否则进入该子树,继续深度优先搜索。
回溯法解问题的所有解时,必须回溯到根节点,且根节点的所有子树都被搜索后才结束。回 溯法解问题的一个解时,只要搜索到问题的一个解就可结束。
回溯的基本步骤
1. 定义问题的解空间
2. 确定易于搜索的解空间结构
3. 以深度优先搜索的策略搜索解空间,并在搜索过程中尽可能避免无效搜索
某企业面试题:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以 从矩阵中任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了 矩阵的某一格,那么该路径不能再次进入该格子。例如在下面的 3×4 的矩阵中包含一条字符串 “bfce”的路径(路径中的字母用下划线标出)。但矩阵中不包含字符串“abfb”的路径,因为 字符串的第一个字符 b 占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
A | B | T | G |
C | F | C | S |
J | D | E | H |
解题思路:
首先,在矩阵中任选一个格子作为路径的起点。如果路径上的第 i 个字符不是待搜索的目标字 符 ch,那么这个格子不可能处在路径上的第 i 个位置。如果路径上的第 i 个字符正好是 ch,那么 往相邻的格子寻找路径上的第 i+1 个字符。除在矩阵边界上的格子之外,其他格子都有 4 个相邻 的格子。重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。 由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识 路径是否已经进入每个格子。 当矩阵中坐标为(row, col)的格子和路径字符串中相应的字符一 样时,从 4 个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中 下一个字符, 如果 4 个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字 符在矩阵中的定位不正确,我们需要回到前一个,然后重新定位。
源码实现:
1 #include <stdio.h> 2 #include <string> 3 4 using namespace std; 5 6 bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, 7 const char* str, int& pathLength, bool* visited); 8 /***************************************** 9 功能: 查找矩阵中是否含有 str 指定的字串 10 参数说明: 11 matrix 输入矩阵 12 rows 矩阵行数 13 cols 矩阵列数 14 str 要搜索的字符串 15 返回值: 是否找到 true 是,false 否 16 *******************************************/ 17 18 bool hasPath(const char* matrix, int rows, int cols, const char* str) 19 { 20 if(matrix == nullptr || rows < 1 || cols < 1 || str == nullptr) 21 return false; 22 23 bool *visited = new bool[rows * cols]; 24 memset(visited, 0, rows * cols); 25 int pathLength = 0; 26 27 //遍历矩阵中每个点,做为起点开始进行搜索 28 for(int row = 0; row < rows; ++row) 29 { 30 for(int col = 0; col < cols; ++col) 31 { 32 if(hasPathCore(matrix, rows, cols, row, col, str, pathLength, visited)) 33 { 34 return true; 35 } 36 } 37 } 38 delete[] visited; 39 return false; 40 } 41 42 /*探测下一个字符是否存在*/ 43 bool hasPathCore(const char* matrix, int rows, int cols, int row, 44 int col, const char* str, int& pathLength, bool* visited) 45 { 46 if(str[pathLength] == '\0') 47 return true; 48 bool hasPath = false; 49 if(row >= 0 && row < rows && col >= 0 && col < cols 50 && matrix[row * cols + col] == str[pathLength] 51 && !visited[row * cols + col]) 52 { 53 ++pathLength; 54 visited[row * cols + col] = true; 55 hasPath = hasPathCore(matrix, rows, cols, row, col - 1, str, pathLength, visited) 56 || hasPathCore(matrix, rows, cols, row - 1, col, str, pathLength, visited) 57 || hasPathCore(matrix, rows, cols, row, col + 1, str, pathLength, visited) 58 || hasPathCore(matrix, rows, cols, row + 1, col, str, pathLength, visited); 59 if(!hasPath) 60 { 61 --pathLength; 62 visited[row * cols + col] = false; 63 } 64 } 65 return hasPath; 66 } 67 68 69 /*单元测试代码*/ 70 void Test(const char* testName, const char* matrix, int rows, int cols, 71 const char* str, bool expected) 72 { 73 if(testName != nullptr) 74 printf("%s begins: ", testName); 75 if(hasPath(matrix, rows, cols, str) == expected) 76 printf("Passed.\n"); 77 else 78 printf("FAILED.\n"); 79 } 80 81 //ABTG 82 //CFCS 83 //JDEH 84 //BFCE 85 void Test1() 86 { 87 const char* matrix = "ABTGCFCSJDEH"; 88 const char* str = "BFCE"; 89 Test("功能测试 1", (const char*) matrix, 3, 4, str, true); 90 } 91 92 //ABCE 93 //SFCS 94 //ADEE 95 //SEE 96 void Test2() 97 { 98 const char* matrix = "ABCESFCSADEE"; 99 const char* str = "SEE"; 100 Test("功能测试 2", (const char*) matrix, 3, 4, str, true); 101 } 102 103 //ABTG 104 //CFCS 105 //JDEH 106 //ABFB 107 void Test3() 108 { 109 const char* matrix = "ABTGCFCSJDEH"; 110 const char* str = "ABFB"; 111 Test("功能测试 3", (const char*) matrix, 3, 4, str, false); 112 } 113 114 //ABCEHJIG 115 //SFCSLOPQ 116 //ADEEMNOE 117 //ADIDEJFM 118 //VCEIFGGS 119 //SLHECCEIDEJFGGFIE 120 void Test4() 121 { 122 const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS"; 123 const char* str = "SLHECCEIDEJFGGFIE"; 124 Test("功能测试 4", (const char*) matrix, 5, 8, str, true); 125 } 126 127 //ABCEHJIG 128 //SFCSLOPQ 129 //ADEEMNOE 130 //ADIDEJFM 131 //VCEIFGGS 132 //SGGFIECVAASABCEHJIGQEM 133 void Test5() 134 { 135 const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS"; 136 const char* str = "SGGFIECVAASABCEHJIGQEM"; 137 Test("功能测试 5", (const char*) matrix, 5, 8, str, true); 138 } 139 140 //ABCEHJIG 141 //SFCSLOPQ 142 //ADEEMNOE 143 //ADIDEJFM 144 //VCEIFGGS 145 //SGGFIECVAASABCEEJIGOEM 146 void Test6() 147 { 148 const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS"; 149 const char* str = "SGGFIECVAASABCEEJIGOEM"; 150 Test("功能测试 6", (const char*) matrix, 5, 8, str, false); 151 } 152 153 //ABCEHJIG 154 //SFCSLOPQ 155 //ADEEMNOE 156 //ADIDEJFM 157 //VCEIFGGS 158 //SGGFIECVAASABCEHJIGQEMS 159 void Test7() 160 { 161 const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS"; 162 const char* str = "SGGFIECVAASABCEHJIGQEMS"; 163 Test("功能测试 7", (const char*) matrix, 5, 8, str, false); 164 } 165 166 //AAAA 167 //AAAA 168 //AAAA 169 //AAAAAAAAAAAA 170 void Test8() 171 { 172 const char* matrix = "AAAAAAAAAAAA"; 173 const char* str = "AAAAAAAAAAAA"; 174 Test("边界值测试 8", (const char*) matrix, 3, 4, str, true); 175 } 176 177 //AAAA 178 //AAAA 179 //AAAA 180 //AAAAAAAAAAAAA 181 void Test9() 182 { 183 const char* matrix = "AAAAAAAAAAAA"; 184 const char* str = "AAAAAAAAAAAAA"; 185 Test("边界值测试 9", (const char*) matrix, 3, 4, str, false); 186 } 187 188 //A 189 //A 190 void Test10() 191 { 192 const char* matrix = "A"; 193 const char* str = "A"; 194 Test("边界值测试 10", (const char*) matrix, 1, 1, str, true); 195 } 196 197 //A 198 //B 199 void Test11() 200 { 201 const char* matrix = "A"; 202 const char* str = "B"; 203 Test("边界值测试 11", (const char*) matrix, 1, 1, str, false); 204 } 205 206 void Test12() 207 { 208 Test("特殊情况测试 12", nullptr, 0, 0, nullptr, false); 209 } 210 211 int main(int argc, char* argv[]) 212 { 213 Test1(); 214 Test2(); 215 Test3(); 216 Test4(); 217 Test5(); 218 Test6(); 219 Test7(); 220 Test8(); 221 Test9(); 222 Test10(); 223 Test11(); 224 Test12(); 225 system("pause"); 226 return 0; 227 }
==========================================================================================================================