[编程题]有趣的排序(某公司笔试原题)

题目链接:题目链接在此.
来源:牛客网

题目描述:
度度熊有一个N个数的数组,他想将数组从小到大 排好序,但是萌萌的度度熊只会下面这个操作:
任取数组中的一个数然后将它放置在数组的最后一个位置。
问最少操作多少次可以使得数组从小到大有序?

输入描述:
首先输入一个正整数N,接下来的一行输入N个整数。(N <= 50, 每个数的绝对值小于等于1000)

输出描述:
输出一个整数表示最少的操作次数。

示例1
输入
4
19 7 8 25
输出
2

题目解析:

第一种方法:
由于度度熊每次只能选择一个拿到最后,对于例子 19,7,8,25而言,可以先把 19 放到最后,之后再将 25 放到最后,通过两次移动即可完成排序。(或者直接寻找逆序对也可以?)
仔细观察以下两个数组(原始与排好序的)发现
19,7,8,25
7,8,19,25
只有7,8无需移动,所以我们上下对照,计算不需要移动的数字个数,也就是从最小值开始统计连续的从小到大排序的数字个数小数必须在大数前面,且统计的第一个数字前面不能有比最后一个数字小的数。举例说明一下,即:上面数组第一个元素与下面数组第一个元素比较,19>7,所以上面第二个元素与下面第一个元素再次比较,发现相等,计数加一,上下数组指针同时向后移动一位,比较上面第三个元素与下面第二个元素,发现相等,计数再加一,继续后移,比较25与19,25>19且到达上面数组末尾元素,结束比较。最后基数为2,即不需要移动的数字个数为2.最后输出 4-2=2,即为操作次数

程序如下:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
//两个数组对比
  int n,temp,a[50];
    cin>>n;
    vector<int> v;
    for(int i=0;i<n;i++)
    {
        cin>>temp;
        a[i]=temp;
        v.push_back(temp);
    }
    sort(v.begin(),v.end());
    int k=0,count=0;
    for(int j=0;j<n;j++)
    {
        if(a[j]==v[k])
        {
            count++;
            k++;
        }
    }
    cout<<n-count<<endl;
}

第二种方法:
利用map寻找排序后键值大于后面元素键值的个数,即需要移动的次数。具体方法如下:
举例说明:
对于19,7,8,25来说,记录每个元素的键值 0,1,2,3
排序后为7,8,19,25,对应的键值分别为 1,2,0,3.
则 2>0,count+1=1,19对应的键值更改为n+1=5,相当于认为将 19 移动到数组末尾 : —,7,8,25,19
之后 5>3,25 对应键值改为 6,即移动到 19 后面,count+1=2.即:—,7,8,—,19,25
最后一共移动两次

程序如下:

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
int main()
{
    //利用map键值对比
    int n,temp;
    cin>>n;
    vector<int> v;
    map<int,int> m;
    for(int i=0;i<n;i++)
    {
        cin>>temp;
        v.push_back(temp);
        m[temp]=i;
    }
    sort(v.begin(),v.end());
    int count=0,t=n;
    for(int j=0;j<n-1;j++)
    {//举例:对于19,7,8,25来说,排序后为7,8,19,25,对应的键值(value)分别为
     //1,2,0,3.则2>0,count+1=1,19对应的键值更改为5,相当于认为移动到数组末尾
     //之后5>3,25对应键值改为6,即移动到19后面,count+1=2.最后一共移动两次
        if(m[v[j]]>m[v[j+1]])
        {
            m[v[j+1]]=++t;
            count++;
        }
    }
    cout<<count<<endl;
}
over~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值