LeetCode: Merge Two Sorted Lists, Remove Duplicates/Element, strStr()

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 // 匹配成功
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值