LeetCode 刷题 (三)算法基础

82. 删除排序链表中的重复元素 II

        思路:首先,我们初始一个新的结点ans,由于第一个元素也可能重复,所以我们需要让ans成为新的头结点。然后我们开始遍历链表,如果当前位置的结点cur满足cur.next==cur.next.next,那么我们记录cur.next的值x,然后遍历链表,去删除后续所有为x的结点。如果cur.next!=cur.next.next,则cur.next是不重复的元素,我没呢让cur = cur.next;重复上面的操作,直到链表结束。最后记得让ans = ans->next.因为我们初始化的那个结点,在最初的链表中是不存在的。

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (!head) {
            return head;
        }
        
        ListNode* ans = new ListNode(0, head);

        ListNode* cur = ans;
        while (cur->next && cur->next->next) {
            if (cur->next->val == cur->next->next->val) {
                int x = cur->next->val;
                while (cur->next && cur->next->val == x) {
                    cur->next = cur->next->next;
                }
            }
            else {
                cur = cur->next;
            }
        }

        return ans->next;
    }
};

15. 三数之和

思路:首先,由于题目要求三元组不能重复,所以我们可以对数组进行排序,然后从小到大一次去暴力求解a,b,c。这个时候仍然有可能重复,因为元素有重复的情况。因此我们每次遍历时都要保证与之前的元素不相等。三个for循环直接暴力求解。这个显然不是很好的选择,时间复杂度太大了。进一步,由于我们要找的是满足a+b+c=0的三个值,所以当我们确定了a的值以后,问题就退化为两数之和的问题了,这个时候我们可以使用双指针法来解决问题。关于两数之和问题,简单说一下,左右两个指针,如果两个数的和大于target,右边的指针右移一位;如果小于target,则左边的指针移动一位。整个算法的时间复杂度为O(N)。

所以三数之和的时间复杂度为O(N^2)

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        int n = nums.size();
        if(n<=3){
                return ans;
        }
        sort(nums.begin(),nums.end());
        //由于我们选择时a<b<c,所以当a>0时,可以直接结束遍历
        for(int ia = 0;ia<n;ia++){
            //和上一次枚举的数不一样
            if (ia > 0 && nums[ia] == nums[ia - 1]) {
                continue;
            }
            //c从右边往左
            int ic = n-1;
            int target = -nums[ia];
            for(int ib =ia+1;ib<n;ib++){
                if(ib>ia+1&&nums[ib] == nums[ib-1]){
                    continue;
                }
                while(ib<ic&&nums[ib]+nums[ic]>target){
                    ic--;
                }
                if(ib>=ic){
                    break;
                }
                if(nums[ib]+nums[ic]==target){
                    ans.push_back({nums[ia],nums[ib],nums[ic]});
                }
            }
        }
        return ans;

    }
};

844. 比较含退格的字符串

思路:我们可以利用栈思想来解决这个问题,由于栈的先进后出原则,当我们遇到退格字符时,我们很方便的删去的前一个字符。最后我们统计两个栈内的字符是否一致即可.

class Solution {
public:
    string made(string str) {
        string ret;
        for (int i =0;i<str.length();i++) {
            if (str[i] != '#') {
                //在尾部添加一个元素
                ret.push_back(str[i]);
            } else if (!ret.empty()) {
                //删除最后一个元素,如果有的话
                ret.pop_back();
            }
        }
        return ret;
    }
    bool backspaceCompare(string s, string t) {
        return made(s)==made(t);
    }
};

986. 区间列表的交集

思路:见图解:

        

 由于first和second里面的集合都是不相交的,所以几种情况分析一下就可以很好的解决问题。

class Solution {
public:
    vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList) {
        int n = firstList.size(), m = secondList.size();
        vector<vector<int>> ans;
        if(n == 0 || m == 0) return ans;
        int i=0, j=0;
        while(i<n && j<m){
            // 求左右边界,有交集则加入ans
            int left = max(firstList[i][0], secondList[j][0]);
            int right = min(firstList[i][1], secondList[j][1]);
            if(right >= left) 
                ans.push_back({left, right});
            // 见图解很容易了解到,我们每次处理完以后都要讲右端点小的那个区间放弃,留下大的继续下一轮
            if(firstList[i][1] < secondList[j][1]) 
                i++;
            else
                j++;
        }
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值