ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

旋转数组的解法——牛客算法入门题

2021-06-01 21:34:49  阅读:145  来源: 互联网

标签:入门 int 元素 param 牛客 vector 整型 数组 解法


题目来源:旋转数组_牛客题霸_牛客网 (nowcoder.com)

题目描述

一个数组A中存有N(N&gt0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0 A1 ……AN-1 )变换为(AN-M …… AN-1 A0 A1 ……AN-M-1 )(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

示例1

输入:
6,2,[1,2,3,4,5,6]
返回值:
[5,6,1,2,3,4]

备注:

(1<=N<=100,M>=0)




解法1:
对数组中元素进行遍历,遍历过程中将每个元素直接移动至应在的位置。(自己动手画一画就知道了)
class Solution {
public:
    /**
     * 旋转数组
     * @param n int整型 数组长度
     * @param m int整型 右移距离
     * @param a int整型vector 给定数组
     * @return int整型vector
     */
    vector<int> solve(int n, int m, vector<int>& a)
    {
        // write code here
        if(m%n == 0)
            return a;           //若所要移动的位置是元素总数的整数倍,则相当于没移动。
        else
            m %= n;            //否则将右移距离除以元素总数取余。此举是为了减少计算移动后下标的计算量。
        int temp1,temp2;         //临时存储中间变量
        int new_pos,idx = 0,i =0,cnt =0;//new_pos为当前元素移动后的下标,cnt指目前已移动了多少个元素,idx为移动的轮数,同时也代表每轮初始移动元素的下标,i指代当前元素移动前的下标。
            
        for(idx;idx<=m;idx++)
        {
            
            if(cnt >= n)         //所有元素均移动完毕
                break;
            temp1=a[idx];        //暂存当前元素
            i = idx;           //初始化当前元素下标
            while((i+m)%n!= idx)    //只要当前元素移动后的下标不是最初的下标便继续循环。亦即移动这一轮的最后一个元素之前结束循环。
            {
                new_pos = (i+m)%n;  //新的下标=旧下标+移动位数 与元素总数n取余。
                temp2 = a[new_pos];  //暂存当前新下标中的元素
                a[new_pos] = temp1;  //移动到新下标中
                i = new_pos;      //下一个处理的是之前存放在新下标中的老元素
                temp1 = temp2;     //temp1为即将进行移动的元素值
                cnt++;          //已经完成了一次移动
            }
            a[idx] = temp1;       //移动这一轮最后一个元素到新下标。由于每轮最后一次移动的元素的新下标为这一轮移动的第一个元素的老下标,形成了一个闭环,所以不再继续。
            cnt++;            //完成最后一次移动
            }
        return a;            //循环结束即代表已完成了所有的移动任务。返回。
    }
};

同种思想的另一种写法: 

 

class Solution {
public:
    /**
     * 旋转数组
     * @param n int整型 数组长度
     * @param m int整型 右移距离
     * @param a int整型vector 给定数组
     * @return int整型vector
     */
    vector<int> solve(int n, int m, vector<int>& a) {
        // write code here
        int start = 0;
        int pos = start;
        int count = 0;
        int tmp1 = a[start];
        int tmp2 = tmp1;
        m = m % n;
        while(true)
        {
            tmp1 = a[(pos + m) % n];
            a[(pos + m) % n] = tmp2;
            tmp2= tmp1;
            pos = (pos + m) % n;
            count ++;
            if(count == n)
                break;
            if(pos == start)
            {
                start = start + 1;
                pos = start;
                tmp1 = a[start];
                tmp2 = a[start];
            }
        }
        return a;
    }
};

 

 

 

 

 解法2:

  这个解法应该是这道题名字的由来,这也是网上最普遍的解法,即三次旋转解决问题。

 

  该方法基于如下的事实:当我们将数组的元素向右移动 k 次后,尾部 k mod n 个元素会移动至数组头部,其余元素向后移动 k mod n个位置。

 

  该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的 k mod n个元素就被移至数组头部,然后我们再翻转 [0, k mod n-1]区间的元素和 [k mod n, n-1]区间的元素即能得到最后的答案。

  这里自己写了个reverse函数用于旋转数组。

class Solution {
public:
    /**
     * 旋转数组
     * @param n int整型 数组长度
     * @param m int整型 右移距离
     * @param a int整型vector 给定数组
     * @return int整型vector
     */
    void reverse(vector<int>& a,int start,int end){
        while(start<end){
            swap(a[start],a[end]);
            start++;
            end--;
 
        }
    }
    vector<int> solve(int n, int m, vector<int>& a) {
        m=m%n;
        reverse(a,0,n-1);
        reverse(a,0,m-1);
        reverse(a,m,n-1);
 
        return a;
    }
 
};

 

  

  这里充分运用了vector数组对象的方法begin()和end()以及STL中algorithm库的算法reverse,简化了步骤。

class Solution {
  public:
    /**
     * 旋转数组
     * @param n int整型 数组长度
     * @param m int整型 右移距离
     * @param a int整型vector 给定数组
     * @return int整型vector
     */
    vector<int> solve(int n, int m, vector<int> &a) {
        // write code here
 
        if (!n)
            return a;
        if (!m)
            return a;
        m %= n;
 
        reverse(a.begin(), a.end());
        reverse(a.begin(), a.begin() + m);
        reverse(a.begin() + m , a.end());
        return a;
    }
};

 

解法3:

此法抓住了题目的漏洞,既然题目不允许声明另外的数组,那我直接在你给的vector数组后面追加一模一样的元素。实质是使用辅助数组来直接移动。

该法同样活用了vector类的成员函数push_back(int),pop_back(),分别代表在数组尾部追加与删除元素。

class Solution {
public:
    /**
     * 旋转数组
     * @param n int整型 数组长度
     * @param m int整型 右移距离
     * @param a int整型vector 给定数组
     * @return int整型vector
     */
    vector<int> solve(int n, int m, vector<int>& a) {
        // write code here
        int M = m%n;
        for(int i = 0; i < n; i++)
        {
            a.push_back(a[i]);
        }
        for(int i = 0; i < n; i++)
        {
            a[i] = a[i+n-M];
        }
        for(int i = 0;i<n;i++)
        {
            a.pop_back();
        }
        return a;
        //return
    }
};

 

 

 

参考来源:旋转数组__牛客网 (nowcoder.com)

标签:入门,int,元素,param,牛客,vector,整型,数组,解法
来源: https://www.cnblogs.com/boeisolation/p/14838947.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有