【递归+回溯】

题目介绍

已知数据格式,实现一个函数 fn ,给一个 id 找出链条中其对应的所有的父级 name
示例1: 传入 id ddrr2, 返回 广东省深圳市福田区A街道
示例2: 传入 id sdsd, 返回 广东省深圳市

const cityData = [{
 id: 'axzx',
 name: '广东省',
 children: [
   {
     id: 'sdsd',
     name: '深圳市',
     children: [
       {
         id: '45dss',
         name: '南山区'
       },
       {
         id: 'sdsd11',
         name: '福田区',
         children: [{
           id: 'ddrr2',
           name: 'A街道'
         }]
       }
     ]
   },
   {
     id: '2323d',
     name: '东莞市',
     children: [
       {
         id: 'xxs2',
         name: 'A区'
       },
       {
         id: 'kklio2',
         name: 'B区',
       }
     ]
   }
 ]
}];

题解

这是三级地址select组件最常用的算法,可以将数组结构看成一棵树,然后用递归+回溯的方法做,首先可以思考递归出口以及每一层递归的函数传参,这道题目递归出口有两种情况:第一种找到了对应的id,第二种情况已经遍历到当前最后一层还没找到。(第一种情况需要结束整个函数并return出结果,第二种情况需要结束当前递归并回到上一层状态)

在这里插入图片描述

function search(id,data){
    // 1.递归函数
    function recurse(currentData){
        // 2. 递归出口
        if(currentData?.id===id) return;
        if(!currentData?.children) return;
        for(const v of currentData){
            recurse(v?.children);
        }
        
    }
    for(const v of data){
        recurse(v);  
    }
}

根据题意还需要一个res数组在每次递归时将当前遍历对象的name push进去,并且两种递归出口后续操作完全不同,所以在代码中新增一个res并且修改递归出口函数。

function search(id,data){
    let res = [];
    // 1.递归函数
    function recurse(currentData){
        // 2. 递归出口
        if(currentData?.id===id) return true;
        if(!currentData.children) return false;
        for(const v of currentData.children){
            res.push(v.name);
            const flag = recurse(v);
            if(flag){
                return true;
            }
            // 回溯
            res.pop();
        }
        
    }
    for(const v of data){
        res.push(v.name);
        const flag = recurse(v);
        if(flag){
            console.log(res);
            return res.join('');
        }
        // 回溯
        res.pop();
    }
}

回溯模板

上述题目中当当前节点无子节点退出当前递归后需要执行回溯算法,回溯算法可以套用下面框架

function main(){
	function curse(){
		/*递归出口*/
		for(){
			/**状态压入*/
			curse();
			/**回溯,状态推出 */
		}
	}
	curse(); 
}

拓展(leetcode17、22、46、77、79、78)

leetcode17 链接: 电话号码的字母组合
leetcode22 链接: 括号生成
leetcode46 链接: 全排列
leetcode77 链接: 组合
leetcode78 链接: 子集
leetcode79 链接: 单词搜索

类似题目都可以去根据上述思路来做,先递归到最后一层节点,如果满足题意,那么直接return,如果不满足,回溯到上一节点压入另外的状态继续递归,直到满足题目要求为止。注意递归中每一层的需要遍历哪些数据,比如电话号码字母组合中的需要遍历当前数字的所有字母。

var letterCombinations = function(digits) {
	let matrix = ['','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz'];
	function curse(i){
		/**出口 */
		for(const v of matrix[digits[i]]){
			/**状态压入 */
			curse(i+1);
			/**状态pop*/
		}
	}
	curse(0)
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值