• CSP-J 2023 入门级 第一轮 完善程序(1)


    【题目】

    CSP-J 2023 入门级 第一轮 完善程序(1)
    (1)(寻找被移除的元素)问题:原有长度为n+1、公差为1的等差升序数列;将数列输入到程序的数组时移除了一个元素,导致长度为n的升序数组可能不再连续,除非被移除的是第一个或最后一个元素。需要在数组不连续时,找出被移除的元素。
    试补全程序。

    #include 
    #include 
    using namespace std;
    int find_missing(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == mid +) {} else {}
        }
        return}
    
    int main() {
        int n;
        cin >> n;
        vector<int> nums(n);
        for(int i = 0; i < n; i++)cin >> nums[i];
        int missing_number = find_missing(nums);
        if (missing_number ==) {
            cout << "Sequence is consecutive" << endl;
        } else {
            cout << "Missing number is " << missing_number << endl;
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    1. ①处应该填( )
      A. 1 B. nums[0] C. right D. left
    2. ②处应该填( )
      A. left = mid + 1 B. right = mid – 1
      C. right = mid D. left = mid
    3. ③处应该填( )
      A. left = mid + 1 B. right = mid – 1
      C. right = mid D. left = mid
    4. ④处应该填( )
      A. left + nums[0] B. right + nums[0]
      C. mid + nums[0] D. right + 1
    5. ⑤处应该填( )
      A. nums[0]+n B. nums[0]+n-1 C. nums[0]+n+1 D. nums[n-1]

    【题目考点】

    1. 二分查找

    【解题思路】

    先看主函数

    int main() {
        int n;
        cin >> n;
        vector<int> nums(n);
        for(int i = 0; i < n; i++)cin >> nums[i];
        int missing_number = find_missing(nums);
        if (missing_number ==) {
            cout << "Sequence is consecutive" << endl;
        } else {
            cout << "Missing number is " << missing_number << endl;
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    输入n,输入n个元素保存在顺序表nums中,下标0~n-1。根据题目,等差数列公差为1,一共n+1个数字,如果被移除的不是nums[0],那么这n+1个数字最小值为nums[0],最大值应该为nums[0]+n,在这n+1个数中移除一个数字。
    调用find_missing函数,查找丢失的数字,赋值给missing_number。
    如果丢失的数字是(5),那么输出“序列是连续的”,否则输出丢失的数字。
    也就是说如果丢失的数字是n+1个数字中的第1个或最后一个,find_missing函数会返回(5)处应该填的值,此时整个序列就是连续的。

    int find_missing(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == mid +) {} else {}
         }
         return}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    而后看find_missing函数,传入是的nums的引用。看这一代码结构,有left, right, mid,自然是使用了二分查找算法。
    设为nums的元素下标从0~nums.size()-1,先将left, right指向nums保存的序列的两端。
    只要left < right,每次循环取中点位置mid为mid = left+(right-left)/2,该写法在数学意义上等价于mid = (left+right)/2

    之所以写成mid = left+(right-left)/2,是因为这个写法可以保证即使left+right的值超过int可以表示的数值范围,仍能正确求出(left+right)/2的值

    在整数域二分查找算法中,如果取中点的写法为mid = (left+right)/2,那么就是在求满足某一条件的最小值的最小下标。(反之,如果取中点的写法为mid = (left+right+1)/2,那么就是在求满足某一条件的最大值的最大下标。)
    该题要找的是缺失的数字,那么二分查找的条件就可以是“大于缺失数字”,二分查找后找到的是“大于缺失数字的最小值的最小下标”。
    二分查找的过程中,要始终保持要寻找的值的下标在left~right范围之内。

    • 如果mid满足条件“大于缺失数字”,则看看有没有满足条件的更小的数字,取左半边,mid满足条件应该保留在left~right范围之内,所以应该让right = mid
    • 如果mid不满足条件“大于缺失数字”,则应该找更大的数字让其满足条件,取右半边,mid不满足条件应该在left~right范围之外,所以应该让left = mid+1

    设数字序列起始值为s,去掉的数字为s+m。

    012m-1mm+1n-1n
    原数字序列ss+1s+2s+m-1s+ms+m+1s+n-1s+n
    去掉m后的序列:numsss+1s+2s+m-1s+m+1s+m+2s+n

    可以看到,在下标小于m的范围内,nums[i]的值应该等于s+i,下标大于等于m时,nums[i]的值应该等于s+i-1
    假设去掉的数字不是第一个数字s,起始数字s就是nums[0]nums[mid]应该与mid+nums[0]比较,(1)处应该填nums[0],选B。

    • 如果nums[mid]的值是mid+nums[0],那么mid一定小于缺失的数字,不满足条件“大于缺失数字”,应该让left = mid+1,(2)处选A。
    • 如果nums[mid]的值不是mid+nums[0],那么mid一定大于缺失的数字,满足条件“大于缺失数字”,应该让right = mid,(3)处选C。

    while循环跳出后,left或right的值就是找到的是"大于缺失数字"的最小值的最小下标,该下标就是上表中的m,缺失的值应该是s+m,也就是代码中的nums[0]+leftnums[0]+right,(4)处选A或B。

    如果去掉的数字就是第一个数字s,或最后一个数字,整个序列是连续的序列,无论mid为何值,都满足nums[mid]==mid+nums[0],按照上述写法运行程序,会不断的改变left,而right不变,直到while循环跳出,此时left与right的值都为right的初始值nums.size()-1,返回值应该为nums[0]+nums.size()-1
    在主函数中,nums的长度nums.size()就是n,因此当整个序列是连续序列时,find_missing函数的返回值missing_number就是nums[0]+n-1,由于序列连续公差为1,nums[0]+n-1就是nums[n-1]
    而当缺失的数字是大于nums[n-2],小于nums[n-1]的数字时,求大于缺失数字的最小值的最小下标,得到的结果(while循环跳出后left或right的值)也是n-1,find_missing函数返回的值也是nums[0]+n-1,此时nums[0]+n-1不为nums[n-1]
    所以只有返回的nums[0]+n-1的值与nums[n-1]的值相等时,序列才是连续的。
    (5)处选D。

    【答案】

    1. B
    2. A
    3. C
    4. A或B
    5. D
  • 相关阅读:
    当我们对组件二次封装时我们在封装什么
    Python 实现http server接收mutipart/form-data文件 方法2
    JavaScript同步与异步
    Android 输入框(EditText)的输入限制,数字英文邮箱,可见\隐藏切换,踩过的坑!
    HTML5 和 CSS3 的新特性--品优购main主体模块制作
    Spring Boot 面试热点(三)
    数据结构——链表
    网络基础1
    05 网络和防火墙等其他
    安卓备份分区----手动查询安卓系统分区信息 导出系统分区的一些基本操作
  • 原文地址:https://blog.csdn.net/lq1990717/article/details/133184629