首页 > 其他分享 >递归-分治

递归-分治

时间:2023-02-03 22:55:21浏览次数:53  
标签:index return 递归 temp 示例 分治 let nums

递归

  • 递归,将问题分解为重叠的子问题,f(n)=f(n-1)+xxx,满足这样的状态转移方程,说明原问题是不是依赖递归子问题,即f(n)依赖f(n-1)
  • 确定递归出口
  • 递归返回时还原现场

78. 子集(模板题)

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同
完整代码
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsets = function(nums) {

    // 对于子集,其实就是每个元素选不选的问题

    // 0 不选
    // 1 选

    // 对于[1,2,3]
    // 0 0 0 []
    
    // [0,1],[0,1],[0,1]


    // let index=0
    var res1=[]

    let temp=[]

    // 不管当前元素选或者不选,是不是都要走到下一层
    const findSubSet=(temp,index)=>{
        // console.log(temp,index)

        if(index===nums.length){
            console.log(temp,index)
            res1.push(Array.from(temp))
            return 
        }
        // 不选
        findSubSet(temp,index+1)
        // 选
        temp.push(nums[index])
        findSubSet(temp,index+1)
        temp.pop()
    }

    

    findSubSet(temp,0)

    return res1

};
  • 注意点:
    • 选或者不选其实是一个背包问题,即背包容量有限的情况下,如何取舍不同的物品

77. 组合(上题的特例)

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

示例 2:

输入:n = 1, k = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n
解题思路
1.还是子集问题,不过子集的个数有限制,为k
完整代码
/**
 * @param {number} n
 * @param {number} k
 * @return {number[][]}
 */
var combine = function(n, k) {

    let s=[]
    let res=[]

    
    const findSubSet=(index)=>{

        // 去除不满满足条件的
        if(s.length>k||s.length+n-index+1<k){

            // 说明子集长度大于k,或者子集的长度+后面的层数都不足以达到k
            return 
        }

        // 递归出口
        if(index===n+1){
            res.push(Array.from(s))
            return 
        }

        // 对于每一个index,选或者不选

        // 不选
        findSubSet(index+1)

        // 选
        s.push(index)
        findSubSet(index+1)
        s.pop(index)
    }

    findSubSet(1)

    return res
};

46. 全排列(模板题)

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

提示:

  • 1 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同
解题思路
1. 递归+visited数组,
2. 每次都选,没有不选的选项
3. 选择是有限制,已经选过的不能在选择
完整代码
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {

    // 1,2,3 的排列,如果不考虑重复的元素 总数为3*3*3

    // 因为不能出现重复的元素,所以会出现死路(不符合条件)和生路(符合条)两种

    // 对于这种路很多的情况,一般需要使用递归来解决

    let res=[]

    // 定义一个递归的算法
    // let path=[]
    const backTrack=(path)=>{
        // 判断n是否已经在数组中

        if(path.length===nums.length){
            // console.log(2)
            res.push(path)
            return 
        }
        
        nums.forEach((item)=>{
            // 每个都选
            // 选择条件限制,选过的不能在再选
            if(path.includes(item)){
            // console.log(1,n)
                return 
            }
            backTrack(path.concat(item))
        })
    }

    backTrack([])
    return res
};

47. 全排列 II

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10
解题思路
1. 和全排列一样
2. 添加了更多的限制条件==> 不能出现重复的排列(因为元素可以相同)
3. 解决方法:使用hash表保证排列的唯一
完整代码
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permuteUnique = function(nums) {

    // 先全排列排出来

    // 我们存一个map

    // key = “1,1,2" 如果key相同,即has(key) 越过

    // 这里三个元素必选,没有不选的选项
    let res=[]

    let map=new Map()

    let visited=[]
    
    const allSort=(temp,visitedArr)=>{

        if(temp.length===nums.length){
            // console.log(temp)
            // 判断temp键是否存在
            if(!map.has(temp.join(","))){
                map.set(temp.join(","),Array.from(temp))
            }
            return 
        }

        nums.forEach((item,index)=>{
            if(!visitedArr.includes(index)){
                allSort(temp.concat(item),visitedArr.concat(index))
            }
            // console.log(index)
            
        })

    }

    allSort([],visited)

    map.forEach(item=>{
        res.push(item)
    })

    return res
};

98. 验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

img

输入:root = [2,1,3]
输出:true

示例 2:

img

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:

  • 树中节点数目范围在[1, 104]
  • -231 <= Node.val <= 231 - 1
解题思路
1. 判断一棵树是否有效===>判断其左右子树是否有效
2. 有效的条件
	左子树中的最大值小于根节点的值
	右子树的最小值大于根节点的值
完整代码
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */

// 定义一个数据结构,存储节点数是否有效,即这棵树的最大值和最小值

function NodeInfo(){

    this.isValid=false
    this.maxValue=-Infinity
    this.minValue=Infinity
}

 
var isValidBST = function(root) {

    // 有效的判定
    // 1. 节点的左子树的最大值left.maxValue>root.val
    // 2. 节点的右子树的最小值right.minValue<root.val
    // 3. 所有左子树和右子树自身必须也是二叉搜索树


    // 定义一个判断子树节点是否满足条件的函数
    const checkValid=(root)=>{

        // 说明节点为空,空节点肯定有效
        if(!root){
            let nodeInfo=new NodeInfo()
            nodeInfo.isValid=true
            return nodeInfo 
        }

        let nodeInfo=new NodeInfo()

        let leftNode=checkValid(root.left)
        let rightNode=checkValid(root.right)

        if(leftNode.isValid&&rightNode.isValid&&leftNode.maxValue<root.val&&rightNode.minValue>root.val){
            nodeInfo.isValid=true
        }

        nodeInfo.minValue=Math.min(Math.min(leftNode.minValue,rightNode.minValue),root.val)
        nodeInfo.maxValue=Math.max(Math.max(leftNode.maxValue,rightNode.maxValue),root.val)

        return nodeInfo
    }

    let res=checkValid(root)

    console.log(res.isValid)

    return res.isValid
};

50. Pow(x, n)

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25

提示:

  • -100.0 < x < 100.0
  • -231 <= n <= 231-1
  • -104 <= xn <= 104
完整代码
/**
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function(x, n) {

    // n为偶数时 pow(x,n) pow(x,n/2) *pow(x,n/2)

    // n为奇数时 pow(x,n) pow(x,n/2)*pow(x,n/2)*x

    // 递归出口 n=0 时 1

    // n<0为负数是 pow(x,n) = 1/pow(x,-n)

    console.log(n)


    if(n===0){
        return 1
    }

    if(n<0){
        return 1/myPow(x,-n)
    }



    let temp=myPow(x,Math.floor(n/2))

    if(n%2===0){
        return temp*temp
    }else if(n%2===1){
        return temp*temp*x
    }



};

22. 括号生成

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= n <= 8
解题思路
1. 括号的组合类型,其实实际情况就两种
2. 即()里面套() ,或者()()()....
3. 我们把括号组合的问题分为两个子问题
	一个问题为外层有括号 (a)
	一个问题为外层没有括号 b===()()()...
完整代码
/**
 * @param {number} n
 * @return {string[]}
 */
var generateParenthesis = function(n) {

    // 递归出口
    if(n===0){
        return [""]
    }

    // 分治解决

    // 我们把整体的大括号分为a,b两个子问题

    // a 为括号里面内嵌括号的类型 即(  a  ) 其中a为括号组合,也可分为a,b子问题

    // b 为单独括号类型,即()*n n>=0  如() ()()  ()()()


    // 这么分解,a的外层必定右括号,所有括号个数 1~n


    // 类型组合
    let result=[]
    for(let i=1;i<=n;i++){
        // a类型
        // 因为外层括号算一层
        let result_a=generateParenthesis(i-1)

        // b类型
        let result_b=generateParenthesis(n-i)

        

        for(let a of result_a){

            for(let b of result_b){
                result.push("("+a+")"+b)
                
            }
        }

    }

    return result

};

标签:index,return,递归,temp,示例,分治,let,nums
From: https://www.cnblogs.com/lingxin1123/p/17087613.html

相关文章

  • #yyds干货盘点# LeetCode程序员面试金典: 递归乘法
    题目:递归乘法。写一个递归函数,不使用*运算符,实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。示例1:输入:A=1,B=10输出:10示例2:输入:A=3,B=4......
  • 万字详解递归与递推
    前言相信这个故事,朋友们应该都不陌生,从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?「从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事......
  • BZOJ3262 陌上花开(cdq分治模板)
    Description有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵......
  • 离线分治(cdq)
    离线分治主要是一类用于解决数据结构类型题目的算法,顾名思义,这种算法是一类离线解决问题的分治算法.离线,意味着题目必须能够提前预知整个操作序列而不是只能回答一个操作后......
  • uva839 (二叉树+递归)
    题目链接:​​点击这里​​题目大意就是根据干杠平衡原理,判断题目所给出的数据组成的天平能否平衡。注意,此天平可能包含子天平。输入时,如果w为0,则表示包含子天平,子天平按照......
  • C语言学习: 快速排序(递归方式)
    1#include<stdio.h>2#include"io_utils.h"3#include<stdlib.h>4#include<time.h>56#definePLAYER_COUNT5078voidSwapElements(intarray[......
  • 递归的简单应用
    [递归]母牛的故事(C语言代码)-Dotcpp编程社区(题目在这)1#include<stdio.h>2//找到规律最重要,先尽量多写几个例子,找规律3intf(intn){4if(n<=3)returnn;......
  • 青蛙跳台阶 递归 C语言
    青蛙跳台阶也是一道经典的递归题:一个青蛙,一次可以跳一级台阶,也可以一次跳两级台阶,问当跳n级台阶,有多少种跳法到n等于4的时候,我们发现并不是n=种类那么简单,如果数学底子好,......
  • 二叉树的递归遍历
    二叉树遍历前序遍历staticList<Integer>list=newArrayList<>();//前序遍历publicstaticList<Integer>preorderTraversal(TreeNoderoot){if(......
  • 递归先序输入构造一颗二叉树并输出并求从根结点出发的最大带权和 (c++)
    #include<iostream>#include<cstdio>usingnamespacestd;typedefstructBiTNode//一颗二叉树的结构体{intdata;structBiTNode*lchild,*rchiild;}BiTNode,......