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

来源:互联网 发布:网络商业模式 编辑:程序博客网 时间:2024/05/23 01:18

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

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

 

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 101using 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;}
数组下标用来存储数据,而数组元素存其标志,可以有很多妙用。。

原创粉丝点击