每天一道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-----将链表中满足条件的节点移动到前面
- 每天一道LeetCode-----删除序列中指定元素,将满足要求的元素移动到前面
- 每天一道LeetCode-----有序数组循环右移n位后,寻找最小值,数组中可能包含重复元素
- 每天一道LeetCode-----在给定数组中找到一个子数组,使得这个子数组的元素乘积最大
- 每天一道LeetCode-----摩尔投票法寻找给定数组中出现个数大于n/2或n/3的元素
- 每天一道LeetCode-----给定大小为n+1的数组,元素大小在[1 : n]之间,只有一个元素会重复出现多次,找到重复的那个
- 每天一道LeetCode-----数组序列,每个元素的值表示最多可以向后跳多远,计算最少跳多少次可以到达末尾
- 每天一道leetcode203-移除链表的元素
- 每天一道LeetCode-----从有序数组中删除重复元素
- 每天一道LeetCode-----有序数组右移n位后查找某个元素
- 每天一道LeetCode----从数组中选择若干不连续元素使得总和最大
- 每天一道LeetCode-----合并两个/多个有序链表为一个新链表
- leetcode 2. 从有序链表和数组中移出重复元素 Remove Duplicates
- 每天一道LeetCode-----将数值数组按一定顺序拼接,使得拼接的结果最大
- 每天一道LeetCode-----删除链表倒数第n个节点
- 每天一道LeetCode-----两个有序数组合并后的第K个数
- 每天一道LeetCode--141.Linked List Cycle(链表环问题)
- 每天一道LeetCode-----在有序的二维数组中查找某个元素
- 每天一道LeetCode-----寻找二叉搜索树中第k小的元素
- 每天一道LeetCode-----将单词数组分成多行,每行长度相同,单词之间用空格分隔,要求空格尽量均匀分布