您的位置:首页 > 其它

每天一道LeetCode-----将数组/链表后k个元素移动到前面

2017-11-20 20:38 801 查看

Rotate Array

原题链接Rotate Array



回转一个给定数组k步,本质上是将后k个元素移动到前面(需要保证k小于数组元素个数)

不在原数组上操作的话比较简单,新开一个vector保存回转后的顺序,然后copy到原数组上,时间和空间复杂度都是O(n)

如果需要在原数组上操作的话,就不能有额外的空间使用消耗。那么有如下技巧

将数组后k个元素逆序

将数组前n - k个元素逆序

将整个数组逆序

依次执行上述步骤就完成了回转,以[1,2,3,4,5,6,7]为例,另k为3,那么

将后3个元素逆序,变为[1,2,3,4,7,6,5]

将前4个元素逆序,变为[4,3,2,1,7,6,5]

将整个数组逆序,变为[5,6,7,1,2,3,4]

解释

对于数组的某个子部分,两次逆序等于没有改变,所以前n-k个元素和后k个元素这两部分的内部顺序不会被改变

对于数组的整体而言,只逆序了一次,相当于改变头尾顺序

代码如下

class Solution {
public:
void rotate(vector<int>& nums, int k) {
if(nums.empty() || k <= 0)
return;
int n = nums.size();
/* 防止k大于n,这一步骤让k小于n。因为回转n次等于没有回转 */
k %= n;
std::reverse(nums.begin() + n - k, nums.end());
std::reverse(nums.begin(), nums.begin() + n - k);
std::reverse(nums.begin(), nums.end());
}
};


Rotate List

原题链接Rotate List



回转链表,将后k个非空节点移动到表头。

因为数组可以通过下标定位,所以可以进行三次逆序,但是链表不行,首先不知道链表中节点个数,其次不能够直接定位到倒数第k个非空节点。

问题分两步

确定非空节点个数

从头找第n - k个节点,将其作为最后一个节点,第n - k + 1个节点作为表头

代码如下

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(head == nullptr || k <= 0)
return head;
int n = 1;
ListNode* tail = head;
/* 确定非空节点个数以及最后一个非空节点 */
while(tail->next)
{
++n;
tail = tail->next;
}

/* 另k小于n,如果k不为0,说明仍然需要回转 */
if(k %= n)
{
/* 最后一个节点指向表头
tail->next = head;
/* 找到第n-k个节点,因为head是第一个,所以i从1开始 */
for(int i = 1; i < n - k; ++i)
head = head->next;
/* 第n-k+1个节点变为表头,第n-k个节点变为末尾节点 */
ListNode* res = head->next;
head->next = nullptr;
return res;
}
/* 如果k为0,说明不需要回转,直接返回表头 */
else
{
return head;
}
}
};


上面两道题都是将后k个元素移动到前面

对于数组而言,无法像链表一样只改变某几个节点就实现了顺序的改变。但是可以采用三次逆序的方式改变整体的顺序,弥补缺陷

对于链表而言,无法像数组一样直接确定元素个数和定位某个元素,需要分别求得才可以。但是可以通过改变某些节点以达到顺序的改变

二者都需要考虑边界条件,链表最为明显,需要考虑表头以及null节点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode
相关文章推荐