边界值的处理方法与思考乱炖

本文深入探讨了边界处理在算法设计中的重要性,特别是在二分查找、动态规划和查找区间中的应用。通过对LeetCode题目实例的分析,揭示了边界值在防止溢出、简化问题和加速收敛等方面的作用。

1、边界作用

直接得出结果

例如经常对输入数组进行判断,如果元素为0的话,直接返回结果。
就像随便翻到的lc上338题比特位计数,如果是0或者1的话,直接就可以得出结果。并且0、1是用来作为动态规划的起点的。

作为异常

例如游戏里叠BUFF,经常程序员会用int作为属性数值类型,如果不进行判断的话,最后会溢出成负值,某个炉石主播就表演过…

分类讨论

就如找两个有序序列arr0和arr1的中位数,考虑i = 0、j = 0、i = m、j = n情况的时候,需要分类讨论处理方法。

2、二分查找中的边界值处理

从分析leetcode第4题的泛化版本,也就是【从两个有序数组中找出合并后第k小的数】问题中,我总结了一下需要边界值处理的三个地方。
我将程序段分为了三个部分:

  • 初始化
  • 算法过程
  • 结果处理

利用三部分这个划分,分析了一下前k小问题的边界值处理:
先做一下变量解析,下文会提到三个主要变量i,j,k,其中i为有序数组a的索引,j为有序数组b的索引,k为合并后数组前k小的k。

本题处在两种不同思路的解法,基于i的二分查找,基于k的二分排除。

2.1 初始化。基于i的二分查找中会在这里确定查找范围[imin, imax],i必须满足以下条件:
- 0 <= i <= m;
- 0 <= j <= n;
- i + j = k;

由于lc上的题目是求中值,官解中用了一种取巧的办法来达成以上条件,其实我个人认为并不值得效仿,既不优雅,也不泛用。
以下来自lc第4题官解:

//由于是中值,所以i + j = (m + n + 1) / 2
//推导出,j = (m + n + 1)/2 - i
//推导出只要m <= n就可以保证条件0 <= j <= m
	if (m > n) { // to ensure m<=n
	   int[] temp = A; A = B; B = temp;
	   int tmp = m; m = n; n = tmp;

以下来自nojoker评论的边界处理部分:

//这是通过简单的数学推导得出的
//其实求k小是有专门的论文的,论文中的边界处理正是类似这样的
//本人才疏学浅,看到这位大佬的评论后,再看论文才恍然大悟
 int le=max(0,int(k-nums2.size())),ri=min(k,int(nums1.size()));

2.2 算法过程。基于k的二分排除解法中,会有类似的一小段:

	//伪码
	d1 = k / 2;
	d2 = k - d1;
	compare(a[d1 - 1], b[d2-1]);

问题来了,a[d1 - 1]和b[d2 - 1]是否会越界呢?那完全是有可能的。所以最后应该写成这样:

	//伪码
	d1 = min(len1, k / 2);
	d2 = min(len2, k - d1);
	compare(a[d1 - 1], b[d2-1]);

这样就不会越界了!其实其中还有另一个问题,为何如此排除也是可行的呢?最后能否成功收敛呢?这里我进行过简单的推导,是可行的,这涉及到二分排除背后的机理,只要满足这两个条件,二分排除就可以顺利工作:

  • 区间长度最终收敛到1;
  • 每次选择都能进行有效排除;

其实这也能解析一个问题,为什么compare(a[k/2],b[k/2])最终也能成功得到结果,当k 等于3时,k/2 * 2等于2而不等于3。

2.3 结果处理
少女祈祷中…未完待续。

3、查找区间边界处理方法

二分排除法题解分析中,我得到了一些启发。首先对于查找边界问题,应该要基于两个原则:

  • 索引不能超出查找区间[0, end];
  • end能达到,而不能访问,需要考虑索引到达end时如何处理;

对于二分排除法,其实类似于编译原理中的往前看:

 if (nums1[beg1 + dist1 - 1] < nums2[beg2 + dist2 - 1])
            return findKth(nums1, (beg1 + dist1), end1, nums2, beg2, end2, k - dist1);
        else
            return findKth(nums1, beg1, end1, nums2, (beg2 + dist2), end2, k - dist2);

nums1[beg1 + dist1 - 1]就是类似往前看dist1步,再决定是“前进”还是“停留”。
这个前看阶段,索引并未实际前进,我们其实不必要将其限制在查找区间[0,m]内。beg1 + dist1 - 1越出区间没有问题,只要对其取特值,让其并不可能实际“前进”到区间外即可。所以这里可以有两种解法:

  • 前看时不收缩步长,用特值进行限制,使索引不能真正“前进”到区间外;
  • 前看时收缩步长,这样的话索引便不可能“前进”到区间外;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值