乐趣区

关于算法-数据结构:PAT甲级1085-Perfect-Sequence

题目粗心:

从 N 个正整数中抉择若干个数, 使得选出的这些数中的最大值不超过最小值的 p 倍。问满足条件的抉择计划中,序列最长的长度是多少。

算法思路:

从 N 个正整数中抉择若干个数字组成一个序列,最大值为 M,最小值为 m,那么该序列中的数字,也就是从 m 到 M 的数字肯定是原序列中的间断序列,因为不然就会存在一个数字大于 m 小于 M 不在抉择的序列中,而后将其退出到该序列使其长度变大并且合乎题意,那么原来选出的序列就不是最长的了。所以咱们肯定是在一个有序序列中选出一个间断序列,使其最大值不超过最小值的 p 倍。为此,应用 nums 数组存储输出序列,而后将该序列进行排序,在有序序列中进行查找,这里给出 2 种查找的形式。

算法实现 1:

应用二分查找,这里借助 upper_bound 实现,该函数能够找到第一个大于待查找元素的地位 pos,如果不存在返回数组长度, 那么对于满足 m p>= M 的序列长度就为 pos 减去以后遍历元素的地位。而后每次都应用 ans 记录更大的长度。在 pos 为 N 的时候就没有必要持续往后查问了,因为肯定都满足 m p>=M,并且其长度肯定小于以后的序列长度

算法实现 2:

应用 2 个指针 i 和 j, 初始都指向 0,让 i 指向的元素为 m, 让 j 一值向后走,晓得第一次遇见 nums[i]p<nums[j]时进行,在 j 走动的过程中不断更新其长度 (应用 ans 保留) 而后在 j 进行后让 i 向后走一格,j 接着之前的地位向后持续走(没有从 0 开始向后走),因为 m 增大的时候,小于 j 地位的元素都满足 nums[i]p>= 该元素。同样的在 nums[i]* p 大于序列中最大的元素 max_num 的时候就没有必要查问 j 了。

二分查找的函数阐明:

1、lower_bound(起始地址,完结地址,要查找的数值) 返回的是数值 第一个 呈现的地位。
2、upper_bound(起始地址,完结地址,要查找的数值) 返回的是 第一个大于待查找数值 呈现的地位。
3、binary_search(起始地址,完结地址,要查找的数值)  返回的是是否存在这么一个数,是一个bool 值

提交后果:

AC 代码 1:

#include <cstdio>
#include <algorithm>

using namespace std;

int main(){
    int N,p;
    scanf("%d %d",&N,&p);
    long long nums[N];
    for (int i = 0; i < N; ++i) {scanf("%lld",&nums[i]);
    }
    sort(nums,nums+N);
    long long ans = -1;
    for (int j = 0; j < N; ++j) {long long m = nums[j];
        // 找到第一个大于 m * p 的元素地位, 前一个地位就是满足 m *p>= M 的地位,并且该序列的长度最长
        long long pos = upper_bound(nums+j,nums+N,m*p)-nums;
        long long len = pos-j;
        ans = ans>len?ans:len;
        if(pos==N){
            // 从 j 到 N - 1 的所有的元素都满足 m *p>=M, 无需再遍历后续元素了,其长度肯定比以后短
            break;
        }

    }
    printf("%lld",ans);
    return 0;
}

AC 代码 2:

#include <cstdio>
#include <algorithm>

using namespace std;

int main(){
    int N,p;
    scanf("%d %d",&N,&p);
    long long nums[N];
    long long max_num = -1;
    for (int i = 0; i < N; ++i) {scanf("%lld",&nums[i]);
        max_num = max_num<nums[i]?nums[i]:max_num;
    }
    sort(nums,nums+N);
    long long ans = -1;
    int j=0;
    for (int i=0;i<N;++i) {if(nums[i]*p>=max_num) {//nums[i]* p 大于序列中最大的元素 max_num, 无需再往后遍历了。ans = ans>N-i?ans:N-i;
            break;
        }
        while (j<N){if(nums[i]*p<nums[j]){
                // 找到第一个大于 m * p 的元素
                break;
            }
            ans = ans>j-i+1?ans:j-i+1;
            ++j;
        }
    }
    printf("%lld",ans);
    return 0;
}
退出移动版