题目1 : 二分·二分查找

本文探讨了如何运用二分查找算法解决船舶稀有度排序问题,详细介绍了有序数组和非有序数组下二分查找的应用方法,并通过实例展示了查找特定稀有度船在船队中的排名或确定是否存在重复船只的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Link:http://hihocoder.com/contest/hiho36/problem/1


题目1 : 二分·二分查找

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

Nettle最近在玩《艦これ》,因此Nettle收集了很多很多的船(这里我们假设Nettle氪了很多金,开了无数个船位)。去除掉重复的船之后,还剩下N(1≤N≤1,000,000)种不同的船。每一艘船有一个稀有值,任意两艘船的稀有值都不相同,稀有值越小的船越稀有,价值也就越高。
Nettle现在通过大建又造出了一艘船,他想知道这艘船是不是重复的。如果是重复的,那么这艘船在Nettle所有的船里面稀有值排多少位。

问题一
Nettle已经先把自己所有船按照稀有值从小到大排列好了(a[1..N]),我们要做的是看看新得到的船(假设稀有值为K)是否在这个序列中,且有对应的a[i]=K时,i为多少?

提示一:有序数组的二分查找

问题二
因为Nettle的船太多了,他不愿意去给所有船按照稀有值排序,而是直接告诉了我们每一艘船的稀有值。在这种情况下我们该如何解决这个问题呢?

提示二:非有序数组的二分查找

输入

第1行:2个整数N,K。N表示数组长度,K表示需要查找的数;
第2行:N个整数,表示a[1..N],保证不会出现重复的数,1≤a[i]≤2,000,000,000。

输出

第1行:一个整数t,表示K在数组中是第t小的数,若K不在数组中,输出-1。

样例输入
10 5180
2970 663 5480 4192 4949 1 1387 4428 5180 2761
样例输出
9
[cpp]  view plain copy
  1. //有序排序数组的二分查找,可能存在重复的数  
  2. //查找某一值在排序数组中的第一个位置  
  3. #include <iostream>  
  4. #include <cstdio>  
  5. #include <vector>  
  6. #include <algorithm>  
  7. using namespace std;  
  8.   
  9. int bSearch(int target, vector<int> &A, int n)  
  10. {  
  11.     int left = 0, right = n - 1;  
  12.     int mid;  
  13.     while (left <= right)  
  14.     {  
  15.         mid = (left + right) / 2;  
  16.         if (A[mid] >= target)  
  17.             right = mid - 1;  
  18.         else  
  19.             left = mid + 1;  
  20.     }  
  21.     if (A[left] == target)  
  22.         return left;  
  23.     else  
  24.         return -1;  
  25. }  
  26. vector<int> vec;  
  27. int main()  
  28. {  
  29.     int n, k;  
  30.     scanf("%d%d", &n, &k);  
  31.     /*int v; 
  32.     int t = 1; 
  33.     bool hasV = false; 
  34.     for (int i = 0; i < n; ++i) 
  35.     { 
  36.         scanf("%d", &v); 
  37.         if (v < k) 
  38.             ++t; 
  39.         else if (v == k) 
  40.             hasV = true; 
  41.         else 
  42.             continue; 
  43.     } 
  44.     if (hasV) 
  45.         printf("%d", t); 
  46.     else 
  47.         printf("-1\n"); 
  48.     */  
  49.     //上面的方法没有使用到题目要使用的非有序数组的二分查找  
  50.       
  51.     vec.resize(n);  
  52.     for (int i = 0; i < n; ++i)  
  53.         scanf("%d", &vec[i]);  
  54.     sort(vec.begin(), vec.end());  
  55.     /*int i = 0; 
  56.     while (i < n && vec[i] < k) 
  57.         ++i; 
  58.     if (vec[i] == k) 
  59.         printf("%d\n", i); 
  60.     else 
  61.         printf("-1\n"); 
  62.         */  
  63.     int i = 0;  
  64.     for (i = 0; i < n && vec[i] < k; ++i);  
  65.     if (i < n && vec[i] == k)  
  66.         printf("%d\n", i);  
  67.     else   
  68.         printf("-1\n");  
  69.     //printf("%d\n", bSearch(k, vec, n));  
  70.     return 0;  
  71. }  
  72.   
  73. //使用非有序数组的二分查找,借鉴快速排序的算法,快速排序算法在笔试和面试题中很容易问到,基本就是选取一个值,将比这个值小的数放到左边,将比这个值大的数放到右边,一般这个值的选取可以自己决定,怎样实现这其中的算法呢  
  74. //分别从左从右找不符合条件的数,然后交换  
  75. #include <vector>  
  76. #include <cstdio>  
  77. using namespace std;  
  78. int quickSort(int A[],int target, int left, int right)//这个算法对有重复数的数组应该是不行的吧  
  79. {  
  80.     if (left > right)  
  81.         return -1;  
  82.     int low = left, high = right;  
  83.     int value = A[(left + right) / 2];  
  84.     while (low < high)  
  85.     {  
  86.         while (A[low] < value)//存在重复的数,则这里两边都无法走动  
  87.             ++low;  
  88.         while (A[high] > value)  
  89.             --high;  
  90.         swap(A[low], A[high]);  
  91.     }  
  92.     if (value == target)  
  93.         return low + 1;  
  94.     else if (value > target)  
  95.         return quickSort(A, target, left, low - 1);  
  96.     else  
  97.         return quickSort(A, target, high + 1, right);  
  98. }  
  99. int main(void)  
  100. {  
  101.     int n, k;  
  102.     scanf("%d%d", &n, &k);  
  103.     int a[n];  
  104.     for (int i = 0; i < n; ++i)  
  105.         scanf("%d", &a[i]);  
  106.     printf("%d\n", quickSort(a, k, 0, n - 1));  
  107.     return 0;  
  108. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值