【PAT甲级、C++、贪心、测试点1和2错误分析】1067 Sort with Swap(0, i) (25分)

只是交换数字0和其他数来给数组排序(这个数组的每个数的值和1其索引对应)

下面有测试点1和测试点2错误的代码和错误原因分析

AC代码

# include <iostream>
# include <algorithm>
# include <vector>
# include <unordered_map>

using namespace std;

const int maxn = 100010;
int position[maxn];       // position[i] = 目前数字i在A中的索引

int cnt=0;      // 交换次数
int benwei = 0; // 目前处在本位的数字的数量

// 在交换时计数(这样就不会忘了哈哈哈哈)
void MySwap(int i, int j){
    swap(position[i], position[j]);
    cnt++;
}

// 因为多次用到了position[i] == i,这个意思是判断当前数字i是否已经在本位上
int main()
{
    int N;
    scanf("%d", &N);
    for(int i=0;i<N;++i){
        int num;
        scanf("%d", &num);
        position[num] = i;
        benwei += position[i] == i;
    }
    
    int i=1;  // 要把i定义在外面
    while(benwei < N)
    {
        // 找0的索引
        int pos0 = position[0];
        
        // 如果pos0==0说明0在本位,就随便找个不在本位的数字跟它交换,0又不在本位了
        if(pos0 == 0)
        {
            for(;i<N;++i)  // 不能写成for(int i=1;i<N;++i),i要定义在最外面,不这样测试点1和2会超时
                if(position[i] != i){
                    int posi = position[i];
                    MySwap(0, posi);
                    benwei--;
                    break;
                }
        }
        // 如果0不在本位,就找0所在位置的数来和0交换,这个数就归位了。
        else
        {
            int posshould = position[pos0];
            MySwap(pos0, posshould);
            benwei += position[0] == 0;  // 如果不在本位的0和0号位的其他数字交换了,那么0就归位了,这时就要本位数就要额外+1
            benwei++;
        }
    }
    
    printf("%d\n", cnt);
    
    return 0;
}

一开始写测试点1和2错误的笨蛋代码

数组要取的足够大,不然测试点1和2出现的是段错误而不是运行超时
测试点1和2出现运行超时的原因在32和40行

要这么做的原因
晴神宝典中写的是:

利用每个移回本位的数在后续操作中不再移动的特点,从整体上定义一个变量k,用来保存目前序列中不在本位上的最小数(初始值为1),当交换过程中,出现0回归本位的情况时,总是从当前的k开始继续寻找不在本位的数,这样就能保证复杂度总是线性级别(而不是O(N^2))

其实并不是代码有问题,而是测试数据太大了,自己写的复杂度太高了,导致测试点1和2中的大数据运行过久导致超时(在考试中估计就只能有19分了)

# include <iostream>
# include <algorithm>
# include <vector>

using namespace std;

const int maxn = 10000; // 这里要足够大(100010),不然会出现段错误而不是运行超时
vector<int> A(maxn);
bool OK[maxn] = {false};  // OK[i] 表示数字i是否归位
int cnt=0; 
int benwei = 0;

void MySwap(int i, int j){
    swap(A[i], A[j]);
    cnt++;
}

int main()
{
    int N;
    cin >> N;
    for(int i=0;i<N;++i){
        scanf("%d", &A[i]);
        if(i == A[i]){
            OK[i] = true;
            benwei++;
        }
        else{
            OK[i] = false;
        }
    }
    // int k=1;  // i在这里定义并初始化就不会超时了 
    while(benwei < N)
    {
        auto it = find(A.begin(), A.end(), 0);
        int pos0 = it - A.begin();
        
        if(pos0 == 0)
        {
            for(int k=1;k<N;++k)  // 测试点1和2出现运行超时的原因i要在while外面定义并初始化为1
                if(OK[k] == false){
                    int posk = find(A.begin(), A.end(), k) - A.begin();
                    MySwap(0, posk);
                    OK[0] = false;
                    benwei--;
                    break;
                }
        }
        else
        {
            int posshould = find(A.begin(), A.end(), pos0) - A.begin();
            MySwap(pos0, posshould);
            if(A[0]==0){
                OK[0] = true;
                benwei++;
            }
            OK[pos0] = true;
            benwei++;
        }  
    }
    printf("%d\n", cnt);
    
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值