对分查找应用之列举满足条件的二元组集合

对分查找应用之列举满足条件的二元组集合

余姚二中 梁见斌

题目:列举满足条件的二元组集合。给定一个长度为n的整数数组a和一个目标值s,判断a中是否存在两个元素 a,b,使得a + b = s?找出所有满足条件且不重复的二元组(a, b)。

注意:答案中不可以包含重复的二元组。例如,给定数组 a = (-1, 0, 1, 2, -1, 4, 2, 1, 3), s = 3,则满足要求的二元组集合为:{ (-1, 4), (0, 3), (1, 2)}。

(1)若给定数组 a = (3, -2, -2, 0, -1, 2, 2, 0, 3, -3), s = 0,则满足要求的二元组集合为:{                                           }。(2分)

(2)为实现上述功能,请在划线处填入合适的代码。(4分)

(3)加框代码有误,请改正。(1分)

Dim a(1 To 1000) As Integer

Dim n As Integer

 

Private Sub Command1_Click()

    '为数组a生成n个随机整数,并显示到文本框Text2中,代码略。

End Sub

 

Private Sub Command2_Click()

    Dim i As Integer, j As Integer, p As Integer

    Dim t As Integer, s As Integer

   

    For i = 2 To n '对数组a按升序排序

        t = a(i)

        p = BigerSearch(1, i - 1, t)

        For j = i - 1 To p Step -1

            a(j + 1) = a(j)

        Next j

        a(p+1) = t  

    Next i

    List1.Clear: s = Val(Text3.Text)

    i = 1: j = n

    Do While i < j

        If a(i) + a(j) < s Then

            i = BigerSearch(i + 1, j - 1, s - a(j))

            If a(i - 1) + a(j) = s Then

                List1.AddItem Str(a(i - 1)) + "," + Str(a(j))

            End If

            j = j - 1 '因为此时a(i) + a(j) > s ,故j左移1

        ElseIf a(i) + a(j) > s Then

            j = LessSearch(i + 1, j - 1, s - a(i))

            If a(i) + a(j + 1) = s Then

                List1.AddItem Str(a(i)) + "," + Str(a(j + 1))

            End If

            i = i + 1 '因为此时a(i) + a(j) < s ,故i右移1

        Else

            List1.AddItem Str(a(i)) + "," + Str(a(j))

            Do While i < j And a(i) = a(i + 1) '跳过左侧相同元素

                i = i + 1

            Loop

            Do While i < j And a(j) = a(j - 1) '跳过右侧相同元素

                j = j - 1

            Loop

            i = i + 1: j = j – 1

        End If

    Loop

End Sub

'查找第一个小于key的位置

Private Function LessSearch(ByVal L As Integer, ByVal R As Integer, ByVal key As Integer) As Integer

    Dim m As Integer

    Do While L <= R:

        m = (L + R) \ 2

        If a(m) < key Then L = m + 1 Else R = m - 1

    Loop

    LessSearch =    

End Function

'查找第一个大于key的位置

Private Function BigerSearch(ByVal L As Integer, ByVal R As Integer, ByVal key As Integer) As Integer

    Dim m As Integer

    Do While L <= R:

        m = (L + R) \ 2

        If a(m) <= key Then L = m + 1 Else R = m - 1

    Loop

    BigerSearch =     

End Function

考查知识点:

         插入排序、对分查找算法。要求学生熟悉插入排序和对分查找的算法思想并能熟练运用,根据题意采用相应的代码实现算法思想。

 

参考答案:

(1)(-3, 3), (-2, 2), (0, 0) (无需考虑二元组的顺序,答对1个给1分,全对得2分)

(2)① R  ② L

(3)a(p) = t

 

解析:

         本题的要求是统计满足条件(和为s)的二元组,为了确保没有遗漏和重复,常用的方法是将数组按升序排序,然后分别设置游标i和j作为左右边界,向中间区域扫描查找满足条件的二元组。

         当a(i) + a(j) < s时,说明a(i)太小,需要将i右移,最简单的做法是执行i = i + 1,让左边界i右移1位即可。考虑到数组已经按升序排序,题目采用了对分查找算法,直接将i定位到第一个大于s – a(j)的元素位置,即i = BigerSearch(i + 1, j - 1, s - a(j))。

游标i向右移动过程中,可能指向了某些值恰好等于s – a(j)的元素。因为此时的a(i)是第一个满足a(i) + a(j) > s的元素,若存在这样的元素,则a(i - 1)必定是其中之一。因此,若a(i - 1) + a(j) = s,则说明a(i - 1) 和a(j)就是满足条件的二元组。

将i定位到第一个值大于s – a(j)的位置后,我们执行了语句j = j – 1。这条语句不是必需的,但考虑到此时a(i) + a(j) < s,我们可以直接将j左移1位,这样少执行了一次条件判断,效率更高。

同理,当a(i) + a(j) > s时,采用对分查找,直接将j定位到第一个值小于s – a(i)的位置,即j = LessSearch(i + 1, j - 1, s - a(i))。若a(i) + a(j + 1) = s,则添加二元组a(i) 和a(j + 1)。

当a(i) + a(j) = s时,说明a(i) 和a(j)是满足条件的二元组,为避免输出重复解,我们要分别跳过左右两侧相等的元素。然后分别将i和j向中间移动1位,继续分析[i, j]区域的元素。

题目的难点(也是考点)是使用对分查找算法寻找第一个小于(或大于)key的元素的位置。两个自定义函数LessSearch 和BigerSearch分别实现了上述功能,其中后者在插入排线算法中也用到了。

我们以BigerSearch函数为例说明其中的对分查找算法思想:

因为数组是升序排列的,当a(m) <= key时,说明第一个大于key的元素位于区域[m+1, R],需要更新左边界L = m+1;反之说明第一个大于key的元素位于区域[L, m-1],需要更新右边界R = m-1。

因为循环条件是L <= R,当循环结束时L > R,此时较大的元素是a(L),故返回值为L。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值