天天看点

[LeetCode][189][Rotate Array]

首先,一点题外话。

这是大学学计算机到现在近6年来的时间,第一次认真刷题(PS:中间学习生涯有各种原因碰过两三道。。。)。

作为一个计算机专业出身的程序媴真的很不称职,本科以来,没写过几次代码,算法,数据结构,数据库也一塌糊涂。一直觉得像OJ这么高深厉害的东西我肯定不会,如今浑浑噩噩已经混到研究生要毕业找工作的阶段了,终于抬起手开始练练代码。

好了,作如上铺垫只是为了说明,我将要写的这一系列日志(不知能不能坚持下来)都是自己平时练习时的思路和收获,对其他人不一定具有参考意义。主要是为了记录自己的思维训练过程,方便以后回顾。

首先感谢LeetCode这个平台。https://oj.leetcode.com/

在LeetCode的Algorithms中Easy级别排在最上面的题就是【189】Rotate Array。所以第一道就是它。

(这里插一句,注册好久了,一直没有做是上一次注册后做的第一道题发现只能用Java或者C++,鄙人不才,只有C就会那么一点点,所以以为LeetCode只支持Java或者C++,就一直没做。这次本来是抱着边学Java边做题的节奏刷题来着,后来才发现,原来LeetCode每道题支持的语言种类不一样。。。

[LeetCode][189][Rotate Array]

题目链接:https://oj.leetcode.com/problems/rotate-array/

题目描述:

Rotate an array of n elements to the right by k steps.

For example, with n = 7 and k = 3, the array

[1,2,3,4,5,6,7]

is rotated to

[5,6,7,1,2,3,4]

.

Note:

Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.

Hint:

Could you do it in-place with O(1) extra space?

做这道题的时候第一反映就是我能不能第一次就按照Hint中提到的只用O(1)的空间复杂度。然后想了半天没思路。

(再插一句,写代码一直有个缺点,总想一步到位,写出perfect令人惊叹的代码,所以每次看书写代码都往难了去做,导致每次写代码用的时间很长,遇到的问题很多,反倒继续不下去了。后来得一同学点播,说这样不行,还不太会呢,就给自己提高难度,应该从简单的一点点练起,要不太慢了。这里是为了给跟我有一样强迫症患者的童鞋提个方法,换个思路,说不定有用。)

忽然想到这,我就想那我就用最笨的方法做吧。

所以,方法一:

1. 用一个链表存储数组中后K个数;

2. 将剩下的数从最后一个开始向后移动K位,将这些数移到目标位置;

3. 再将链表的K个节点的数复制给原数组的前K位。

4. 得到目标数组。

方法一只是个思路啦,因为我链表学的不好,所以代码有问题,在LeetCode上一直没通过。。。一会粘一下我的错误代码,留作日后思考和修改。

方法二:

就在我不断想这道题,准备方法一的时候,我忽然想到了方法二,也就是网上普遍的三次反转法。

1.现将整个数组倒转;

2.将数组的前K位倒转;

3.将数组的剩下n-k位倒转;

4.得到目标数组。

开始写代码:

(补充一句,本人英语也不太好,一开始没读懂题,根据题中例子,以为只是把数组的后k位统一挪到数组前面去,后来才知道是一个循环向右移位的问题。所以这道题在一开始还要对k做个简单处理,这里就直接展示读懂题后正确代码了):

void rotate(int nums[], int n, int k) {
    
    if(n == 0 || k == 0){
        return;
    }
    
    int i, temp;
    int m = k%n;   //这里就是前面提到的对k做的简单处理,因为是循环移位,所以k可能大于n,对后面的操作不适用,对n取模后得到要移动的m位
    
    for(i = 0; i < n/2; i++){
        temp = nums[i];
        nums[i] = nums[n-1-i];
        nums[n-1-i] = temp;
    }    //第一次翻转,以中间数字为中心,调换位置,所以只要对数组的前一半元素进行操作即可。因为C语言整除的商无论小数点后是多少,都进行舍位操作,所以这里的中间元素的处理是(n/2);
    
    for(i = 0; i < m/2; i++){
        temp = nums[i];
        nums[i] = nums[m-1-i];
        nums[m-1-i] = temp;
    }    //第二次翻转,对前m位进行翻转,得到前m位的目标位置。
    
    for(i = m; i < (n-m)/2+m; i++){
        temp = nums[i];
        nums[i] = nums[n-1+m-i];
        nums[n-1+m-i] = temp;
    }    //第三次翻转,对剩下的n-m位进行翻转,这里的中间元素要注意一下,因为前面还有m位,所以是(n-m)/2+m,没有测试直接用(n+m)/2是否可以。
    
     /*三次翻转后,得到目标数组。*/
}
           

下面是方法一中未通过的代码,留着日后解决,或者哪位大神好心能帮忙看看~~~

void rotate(int nums[], int n, int k) {
    
    if(n == 0 || k == 0){
        return;
    }
    
    int m = k % n;
    
    typedef struct LNode{
        int data;
        struct LNode * next;
    }ListNode;
    
    ListNode *head, *p, *q;
    head = (ListNode *)malloc(sizeof(ListNode));
    head->data = 0;
    head->next = NULL;
    p = head;
    int i;
    
    for(i = 0; i++; i < m){
        ListNode *node;
        node = (ListNode *)malloc(sizeof(ListNode));
        node->data = nums[n-m+i];
        node->next = NULL;
        p->next = node;
        p = node;
    }
    
    for(i = n-m; i > 0; i--){
        nums[i+m] = nums[i];
    }
    
    q = head->next;
    for(i = 0; i < m; i++){
        nums[i] = q->data;
        q = q->next;
    }
    
}