递归算法-条件式返回

文章介绍了如何在递归算法中使用条件式返回来优化线段树的查询过程。在寻找数组中大于特定值的最小下标时,通过二分法遍历线段树,并利用条件式返回(-1)跳过无效子树,避免了不必要的状态更新,提高了算法效率。这种方法等同于让某些子树的返回值为空,从而达到遍历而不更新状态的效果。
摘要由CSDN通过智能技术生成

递归算法–条件式返回

  1. 前言

函数递归的特点是有去有回,对于底层操作而言,实际上对应着入栈和出栈的过程,直观理解也就是递归过程中无法直接跳出递归,因为栈中仍然保留历史信息。 作为变通的方法,我们可以让某些条件下的递归值不参与返回操作,从而达到“出栈但不出力(状态更新)”的效果。

  1. 问题

直接看一个例子,问题属于线段树大的范畴,利用线段树的技巧求解问题过程中,很多时候需要忽略一些操作,本质上是忽略(改变)左子树或右子树的返回值。如果递归的返回值属于void类型,那么操作相对简单,直接return即可。 显示中经常面临的挑战,返回值属于整数或其它已知数据类型,这种情况下,我们需要采用“蛙跳”技巧,出栈操作必不可少,但是返回操作可以忽略(没有return,直接进行下一步操作)。

问题描述:

给定某一数组a[0…n],并且已知值x,现在要求在数组区间a[l…r]范围内,找到下标i最小对应的数字a[i] ,要求a[i]>x。

这道题可以采用常规的前缀线段树进行求解,二分法是算法通常合理的选择,算法的时间复杂度为(logn)*(logn),这个算法仍有改善的空间。

可以采用二分法遍历线段树,在遍历过程中,选择进入线段树的左子树或者右子树,最后求得某个最大区间完全位于所求解的区间[l…r]的范围内,然后再利用二叉遍历搜索具体的值。

  1. 代码分析

先给出相关的代码,紧接着对这些代码进一步分析,

int get_first(int v, int tl, int tr, int l, int r, int x)
{
    if(l>tr || r<tl) //l.tl...tr..r
    {
        return -1;
    }

    int ls;
    int rs;

    //when tl...tr is in the range of l..tl..tr..r we can move forward
    if(l<=tl && tr<=r)
    {
        if(t[v]<=x)
        {
            return -1;
        }

        int mid;
        

        while(tl!=tr)
        {
            mid=(tl+tr)/2;

            if(t[2*v]>x)
            {
                v=2*v;
                tr=mid;
            }
            else
            {
                v=2*v+1;
                tl=mid+1;
            }
        }

        return tl;
    }

    int tm=(tl+tr)/2;

    ls=get_first(2*v,tl,tm,l,r,x);

    if(ls!=-1)
    {
        return ls;
    }

    rs=get_first(2*v+1,tm+1,tr,l,r,x);

    return rs;
}

看到上面的代码,我们利用-1作为条件判断值,如果ls==-1,那么就跳过左子树的值的返回,直接进入右子树;同理如果t[v]<x,此时我们直接返回-1,在ls/rs=-1的条件下,不予返回值,相当于我们直接跳过了左子树或右子树的值的判断,从而进入下一轮递归。

利用递归树能更形象说明此问题,对于F(8,0,0,1,3)和F(9,1,1,13)两个叶子结点,其返回的标志值都为-1,由于返回值为-1,ls==-1,我们就跳过左子树或右子树更新状态的机会,对其值的上升通道进行“狙击”,让更有效的值获得上升的通道。

在这里插入图片描述

  1. 小结

本问题阐述了递归中的条件式返回的技巧,它相当于整体子树返回的值为空,从而达到遍历但是不更新其状态的效果。今后学习和实践中,也可以采用此技巧进行相关的问题解决。

参考资料:

Segment Tree - Algorithms for Competitive Programming (cp-algorithms.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值