Merge Two Sorted Lists
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {} //C++11初始化列表
* };
*/
先自己想一下。同时遍历两个list,每次将较小的值弹出,放入结果list。其中一个节点全部弹出后,另一个直接链接到结果list的结尾。
时间O(n),n是两个输入list的总长度
空间O(n)
"""
1. Recursion
时间O(n),n是两个输入list的总长度
空间O(n)
"""
"""2. Iteration
和我们一开始的想法很像,但是不使用额外的空间保存计算结果,而是重新连接原有的两个list。
时间O(n),n是两个输入list的总长度
空间O(1)
15 ms, beats 14.06%
"""
class Solution {
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
ListNode dummy(INT_MIN);
ListNode *tail = &dummy;
while (l1 && l2) {
if (l1->val < l2->val) {
tail->next = l1;
l1 = l1->next;
} else {
tail->next = l2;
l2 = l2->next;
}
tail = tail->next;
}
tail->next = l1 ? l1 : l2;
return dummy.next;
}
};
Remove Duplicates from Sorted Array
Given a sorted array, remove the duplicates in-place such that each element appear only once and return the new length.
It doesn’t matter what you leave beyond the new length.
先自己思考一下。
1,1,2,3,4
1,2,1,3,4
1,1,2,2,3
1,2,1,2,3
inplace,且后面可以留无用的数据,直觉是用某种swap。在两个简单例子上试一试,遍历数组,每次数值不增加时,往后遍历直到数值增加(m处),然后和这个不增加的数字swap一下。然后从m+1处继续遍历。
一个紧凑的实现如下
"""1. 26 ms, 61.68%
时间O(n)
空间O(1)
"""
public:
int removeDuplicates(vector<int>& nums) {
int count = 0;
for(int i = 1; i < nums.size(); i++){
if(nums[i] == nums[i-1]) count++;
else nums[i-count] = nums[i]; //amazing
}
return nums.size()-count;
}
Remove Element
Given an array and a value, remove all instances of that value in-place and return the new length.
和前一题很像,代码如下
"""3 ms, beats 61.64%
"""
int removeElement(vector<int>& nums, int val) {
int count = 0;
for(int i = 0; i < nums.size(); i++){
if(nums[i] == val) count++;
else nums[i-count] = nums[i]; //amazing
}
return nums.size()-count;
}
1,2,2,3
2
nums0 = nums0
nums1 = nums3
确实多做了一些赋值操作,注意The order of elements can be changed,所以当需要移除的值比较少时,还可以进一步减少操作的次数。
Now consider cases where the array contains few elements to remove. For example, nums = [1,2,3,5,4], val = 4. The previous algorithm will do unnecessary copy operation of the first four elements. Another example is nums = [4,1,2,3,5], val = 4. It seems unnecessary to move elements [1,2,3,5] one step left as the problem description mentions that the order of elements could be changed.
""" 6 ms, beats 8.10%
"""
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
for(int i = 0; i < size; i++){
if(nums[i] == val) {
nums[i] = nums[size-1];
size --;
i--; //用while能把i++ i--省掉
}
}
return size;
}
""" 6 ms
"""
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
for(int i = 0; i < size; i++){
if(nums[i] == val) {
for(int j=size-1; j>i; j--){
if (nums[j] != val){
nums[i] = nums[j];
break;
}
size --;
}
size --;
}
}
return size;
}
理论上更好的算法时间变更长了,可能和测试集合有关吧。
Implement strStr()
Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Input: haystack = “hello”, needle = “ll”
Output: 2
很简单。
"""1. 暴力搜素
6 ms, beats 26.76%
"""
int strStr(string haystack, string needle) {
int m = needle.length();
if (haystack.size() < m) return -1;
//(haystack.size() == 0 && m == 0) return 0;
for (int i=0; i<=haystack.length()-m; i++){
if (haystack.substr(i, m) == needle)
return i;
}
return -1;
}
上述程序乍一看很好,如果我们没有调用substr函数则更容易发现问题:在haystack.substr(i, m) == needle这步其实是逐位字符比较的。有啥问题参见【算法】KMP算法解析。
一个例子如下:
i: 0 1 2 3 4 5 6 7 8 9 0 1 2
M: a b c d a b c d a b c d e
N: a b c d e // 匹配四位成功后发现a、e不匹配
i: 0 1 2 3 4 5 6 7 8 9 0 1 2
M: a b c d a b c d a b c d e
N: a b c d e // 发现 a、b不匹配
i: 0 1 2 3 4 5 6 7 8 9 0 1 2
M: a b c d a b c d a b c d e
N: a b c d e // 发现 a、c不匹配
i: 0 1 2 3 4 5 6 7 8 9 0 1 2
M: a b c d a b c d a b c d e
N: a b c d e // 发现 a、d不匹配
i: 0 1 2 3 4 5 6 7 8 9 0 1 2
M: a b c d a b c d a b c d e
N: a b c d e // 匹配四位成功后发现a、e不匹配
i: 0 1 2 3 4 5 6 7 8 9 0 1 2 M: a b c d a b c d a b c d e N: a b c d e // 发现 a、b不匹配 i: 0 1 2 3 4 5 6 7 8 9 0 1 2 M: a b c d a b c d a b c d e N: a b c d e // 发现 a、c不匹配 i: 0 1 2 3 4 5 6 7 8 9 0 1 2 M: a b c d a b c d a b c d e N: a b c d e // 发现 a、d不匹配 i: 0 1 2 3 4 5 6 7 8 9 0 1 2 M: a b c d a b c d a b c d e N: a b c d e // 匹配成功