1.猜密码(排列组合问题 —- 回溯)
// 都是数字,都不重复 // 给出范围、最小数字数量?? // 可能的组合:1、数字在范围内的;2、数字和字母分别递增排序;3、每个数字数量大于最小数字数量;4、空返回None // 按字典序输出
// 同:类似洗扑克牌解法,在n张里抽function guessNum(arr, minRange) {// 边界:重复、空、范围不够if (arr.length < minRange || Array.from(new Set(arr)).length !== arr.length) {return;}if (!arr) return "None";// 思路:遍历删n个元素,递归到单次目标范围,剩余数组sortlet res = [];// 1、从最小数字范围开始for (let range = minRange; range < arr.length; range++) {// 1-1、要删去多少个元素let diff = arr.length - range;// 1-2、遍历删去所有可能组合for (let j = 0; j < arr.length; j++) {let restArr = iterator(arr, diff, j);// 2、对剩余数组,按递增排序后,得到单次有效组合,加入结果res.push(restArr.sort((a, b) => a - b));}// 1-3、递归组合function iterator(arr, diff, j) {// 完成目标范围的递归,返回组合后的数组if (!diff) return arr;// 深拷贝数组let cloneArr = [...arr];// 删除单个元素后cloneArr.splice(j, 1);return iterator(cloneArr, diff--);}}// 3、结果按字典序排序输出// 规律:长度同,比较前n个最小的// 前面是从最小范围开始,得到的res数组里的元素长度是由小到大的// 递归组合是按由小到大组合去删去某个元素,得到的剩余数组应该是由大到小// 那么在长度变化的一段起切片,翻转数组后再拼接即可for (let k = 0; k < res.length - 1; k++) {// 长度变化if (res[k].length !== res[k+1].length) {// 切片后拼接let cutArr = res.splice(0,k+1).reverse()res = cutArr.concat(...res)}}return res;}
2.跳格子游戏
地上共有N个格子,你需要跳完地上所有的格子,但是格子间是有强依赖关系的,跳完前一个格子后,后续的格子才会被开启,格子间的依赖关系由多组steps数组给出,steps[0]表示前一个格子,steps[1]表示steps[0]可以开启的格子:比如[0,1]表示从跳完第0个格子以后第1个格子就开启了,比如[2,1],[2,3]表示跳完第2个格子后第1个格子和第3个格子就被开启了请你计算是否能由给出的steps数组跳完所有的格子,如果可以输出yes,否则输出no说明:1.你可以从一个格子跳到任意一个开启的格子2.没有前置依赖条件的格子默认就是开启的3.如果总数是N,则所有的格子编号为[0,1,2,3....N-1]连续的数组输入描述:输入一个整数N表示总共有多少个格子,接着输入多组二维数组steps表示所有格子之间的依赖关系输出描述:如果能按照steps给定的依赖顺序跳完所有的格子输出yes否则输出no示例1输入30 10 2输出yes说明总共有三个格子[0,1,2],跳完0个格子后第1个格子就开启了,跳到第0个格子后第2个格子也被开启了,按照0->1->2或者0->2->1的顺序都可以跳完所有的格子示例2输入21 00 1输出no说明总共有2个格子,第1个格子可以开启第0格子,但是第1个格子又需要第0个格子才能开启,相互依赖,因此无法完成示例3输入60 10 20 30 40 5输出yes说明总共有6个格子,第0个格子可以开启第1,2,3,4,5个格子,所以跳完第0个格子之后其他格子都被开启了,之后按任何顺序可以跳完剩余的格子示例4输入54 30 42 13 2输出yes说明跳完第0个格子可以开启格子4,跳完格子4可以开启格子3,跳完格子3可以开启格子2,跳完格子2可以开启格子1,按照0->4->3->2->1这样就跳完所有的格子示例5输入41 21 0输出yes说明总共4个格子[0,1,2,3],格子1和格子3没有前置条件所以默认开启,格子1可以开启格子0和格子2,所以跳到格子1之后就可以开启所有的格子,因此可以跳完所有格子备注:1 <= N <500steps[i].length=20<=step[i][0],step[i][1]<N
3.欢乐的周末
小华和小为是很要好的朋友,他们约定周末一起吃饭。通过手机交流,他们在地图上选择了多个聚餐地点(由于自然地形等原因,部分聚餐地点不可达),求小华和小为都能到达的聚餐地点有多少个?
输入描述:
第一行输入m和n,m代表地图的长度,n代表地图的宽度。
第二行开始具体输入地图信息,地图信息包含:
0 为通畅的道路
1 为障碍物(且仅1为障碍物)
2 为小华或者小为,地图中必定有且仅有2个 (非障碍物)
3 为被选中的聚餐地点(非障碍物)
输出描述:
可以被两方都到达的聚餐地点数量,行末无空格。
示例1
输入:
4 4
2 1 0 3
0 1 2 1
0 3 0 0
0 0 0 0
输出:
2
说明:
第一行输入地图的长宽为3和4。
第二行开始为具体的地图,其中:3代表小华和小明选择的聚餐地点;2代表小华或者小明(确保有2个);0代表可以通行的位置;1代表不可以通行的位置。此时两者能都能到达的聚餐位置有2处
示例2
输入:
4 4
2 1 2 3
0 1 0 0
0 1 0 0
0 1 0 0
输出:
0
说明:
第一行输入地图的长宽为4和4。
第二行开始为具体的地图,其中:3代表小华和小明选择的聚餐地点;2代表小华或者小明(确保有2个);0代表可以通行的位置;1代表不可以通行的位置。由于图中小华和小为之间有个阻隔,此时,没有两人都能到达的聚餐地址,故而返回0
备注:
地图的长宽为m和n,其中:
4 <= m <= 100
4 <= n <= 100
聚餐的地点数量为 k,则
import java.util.ArrayList;import java.util.List;import java.util.Scanner;public class Main{public static int endX; //餐厅横坐标public static int endY; //餐厅纵坐标public static void main(String[] args) {Scanner sc = new Scanner(System.in);int lenX = sc.nextInt();int lenY = sc.nextInt();int[][] migong = new int[lenX][lenY]; //迷宫数组List<int[]> hw = new ArrayList<>(); //小华和小为的坐标List<int[]> canGuan = new ArrayList<>(); //餐厅的坐标for ( int i=0; i<lenX; i++) {for ( int j=0; j<lenY; j++) {migong[i][j] = sc.nextInt();if (migong[i][j] == 2) {int[] h = { i, j};hw.add(h);} else if (migong[i][j] == 3) {int[] c = { i, j};canGuan.add(c);}}}int[] xh = hw.get(0); //小华的位置坐标int[] xw = hw.get(1); //小为的位置坐标int res = 0;for (int i=0;i<canGuan.size();i++) {int temp[][] = copy(migong); //复制原数组(否则会导致数组改变)endX = canGuan.get(i)[0]; //餐馆横坐标endY = canGuan.get(i)[1]; //餐馆纵坐标if ( forEnd(xh[0],xh[1],temp) == 1 ) {temp = copy(migong);if ( forEnd(xw[0],xw[1],temp) == 1 ) {res++;}}}System.out.println(res);}public static int[][] copy(int[][] nums){int x = nums.length;int y = nums[0].length;int[][] res = new int[x][y];for ( int i=0; i<x; i++) {for ( int j=0; j<y; j++) {res[i][j] = nums[i][j];}}return res;}public static int forEnd(int x,int y,int[][] ints){int U = x - 1; //向上int D = x + 1; //向下int L = y - 1; //向左int R = y + 1; //向右if(x==endX && y==endY){ //到达餐馆返回1return 1;}if (U>=0) { //边界处理if (ints[U][y] != 1) { //只要非1都能通过ints[x][y] = 1; //能通过则本格置为1,表示已经走过if (forEnd(U,y,ints)==1) { //递归处理,若值为1表示可以到达直接return 1return 1;}}}if (D<ints.length) {if (ints[D][y] != 1) {ints[x][y] = 1;if (forEnd(D,y,ints)==1) {return 1;}}}if (L>=0) {if (ints[x][L] !=1 ) {ints[x][y] = 1;if (forEnd(x,L,ints)==1) {return 1;}}}if (R<ints[0].length) {if (ints[x][R] != 1) {ints[x][y] = 1;if (forEnd(x,R,ints)==1) {return 1;}}}return 0;}}
4.解压报文 —- leetcode 394
为了提升数据传输的效率,会对传输的报文进行压缩处理。输入一个压缩后的报文,请返回它解压后的原始报文。
压缩规则:n[str],表示方括号内部的 str 正好重复 n 次。注意 n 为正整数(0 < n <= 100),str只包含小写英文字母,不考虑异常情况。
const decodeString = (s) => {let numStack = []; // 存倍数的栈let strStack = []; // 存 待拼接的str 的栈let num = 0; // 倍数的“搬运工”let result = ''; // 字符串的“搬运工”for (const char of s) { // 逐字符扫描if (!isNaN(char)) { // 遇到数字num = num * 10 + Number(char); // 算出倍数} else if (char == '[') { // 遇到 [strStack.push(result); // result串入栈result = ''; // 入栈后清零numStack.push(num); // 倍数num进入栈等待num = 0; // 入栈后清零} else if (char == ']') { // 遇到 ],两个栈的栈顶出栈let repeatTimes = numStack.pop(); // 获取拷贝次数result = strStack.pop() + result.repeat(repeatTimes); // 构建子串} else {result += char; // 遇到字母,追加给result串}}return result;};
