数组下标的巧用(约瑟夫环等)

数组下标的巧用(约瑟夫环等)

最近在牛客网看到华为的笔试题,如下一题,不难,但觉得遇到好多可以巧用数组下标来存储数据的案例,觉得可以列在一起分享一下。

 

1

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N11000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成去重排序的工作。

Input Param 

     n               输入随机数的个数     

 inputArray      n个随机整数组成的数组 

     

Return Value

     OutputArray    输出处理后的随机整数

 

因为输入的数的个数不限,然后需要去重,再排序。所以大家的下意识常规做法:先排序,这样重复的在一起,然后遍历去重就好了。

 

低效常规做法:

#include<stdio.h>
int main()
{
int n,a[10000],i,j,k,temp;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(a[i]==a[j])
{
for(k=j+1;k<n;k++)
a[k-1]=a[k];
n--;
j--;
}
}
}
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1-i;j++)
{
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for(i=0;i<n;i++)
printf("%d\n",a[i]);
}
}


 

 但海量数据排序,怎么也逃不了两层嵌套循环,效率很低。于是可以这么想,因为输入的数不超过1000,所以可以定义一个1000长度的一维数组,下标可以作为输入的数,如果输入,对应下标的数据置1,标记为已存在,这样下标默认排序了,同时也去重了。下标的妙用如下:

//1-1000随机数,去重,排序(这里只要输入数的范围不是特别大,都可以这么用,输入的个数无所谓)

#include <iostream>
using namespace std;
int main() {
    int N, n;
    while (cin >> N) {
        int a[1001] = { 0 };
        while (N--) {
            cin>> n;
            a[n]= 1;
        }
        for (int i = 0; i < 1001;i++)
            if (a[i])
                cout<< i << endl;
    }
    return 0;
}


 

同样的用法,我想起之前写约瑟夫环的问题:

已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

之前,自己用的循环链表来写,每次不停的去数数,然后遍历,删除节点,再数数,直至所有结点全部剔完。后来用这种方法,数组下标标记法。踢出去置0或者置1标记下就好。效率高了很多。因为数组的查找效率是O(1

class Solution {  
public:  
    int LastRemaining_Solution(unsigned int n, unsigned int m)  
    {  
        if(m==0||n==0)  
            return -1;  
        struct Lnode{  
            int data;  
            Lnode* next;  
        };  
        int len = sizeof(struct Lnode);  
        unsigned int i=1;  
        struct Lnode* head = (struct Lnode*)malloc(len);  
        head->data=0;          //因为需要一个圈,这里是头结点(也就是带数据的),不是头指针。  
        head->next=NULL;  
        struct Lnode* cur = head;  
        while(i<n){  
        struct Lnode* p = (struct Lnode*)malloc(len);  
        p->data=i;  
        p->next=NULL;  
        cur->next = p;  
        cur = p ;  
        i++;  
        }  
        cur->next = head;  //形成循环链表,首尾相连了  
           
          Lnode* q=head;  
          Lnode* pre;        //为下面删除结点定义一个前驱  
    while(n>1){              //删除数到的结点  
         i=0;  
        while(i++<m-1){      //遍历到第m-1个结点  
           pre=q;  
           q=q->next;  
        }  
         pre->next=q->next;  
         free(q);  
          q=pre->next;   
        --n;  
       }  
      return (q->data);    
    }  
};


后来用数组改进:

  

#include<iostream>
#include<cstdlib>
#include<cstring>
#define MAX 101
using namespace std;
int main()
{
    boola[MAX];
    intn,m;
    cin>>n>>m;
    memset(a,0,sizeof(int)*n);
    //memset(a,false,sizeof(int)*n);
 //  for(int i=1;i<=n;++i)a[i]=false;
    intout=0,t=0,s=0;
    do
    {
       ++t;
       if(t==n+1) t=1;
       if(false==a[t]) ++s;
       if(s==m)
       {
         a[t]=true;
         ++out;
         s=0;
         cout<<t<<" ";
       }
    }while(out!=n);
 system("pause");
 return 0;
}
数组下标用来存储数据,而数组元素存其标志,可以有很多妙用。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值