LeetCode刷题之路(第一天)

1、两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]

C++版:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        int n = nums.size();
        int *a = new int[n];
        for(int i = 0;i < n;i++) a[i] = nums[i];
        sort(nums.begin(), nums.end());
        int lhs = 0, rhs = n -1;  //从两边开始查找
        while(rhs > lhs){
            if(nums[rhs] + nums[lhs] > target) rhs--;
            else if(nums[rhs] + nums[lhs] < target) lhs++;
            else{
                int id1, id2;
                for(int i = 0;i < n; i++){
                    if(a[i] == nums[lhs]){
                        id1 = i+1;
                        break;
                    }
                }
                for(int i = n - 1;i >= 0; i--){
                    if(a[i] == nums[rhs]){
                        id2 = i+1;
                        break;
                    }
                }
                res.push_back(min(id1, id2));
                res.push_back(max(id1, id2));
                return res;
            }
        }
    }
};

这种方法首先把给定的Vector进行排序,然后从Vector的两端进行查找,其时间复杂度为O(nlogn),其空间复杂度为O(n)。这种方法相比于暴力求解的算法性能还是提升了一些。但是有没有更好的算法呢?
答案是肯定的,利用哈希表可以用空间换取时间,使得时间复杂度降到O(n)。创建哈希表时要注意,不需要一开始就建立哈希表并扫描全部数据,可以边创建边建立哈希表。代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int> &numbers, int target) {
        map<int, int> hashmap;
        vector<int> res;
        for(int i = 0;i < numbers.size();i++){
            if(hashmap.find(target-numbers[i]) != hashmap.end()){
                res.push_back(hashmap[target-numbers[i]]+1);
                res.push_back(i+1);
                return res;
            }
            hashmap[numbers[i]] = i;
        }
        return res;
    }
};

Python版:

2. 两个排序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
你可以假设 nums1 和 nums2 不同时为空。

示例 1:
nums1 = [1, 3] nums2 = [2]
中位数是 2.0 示例 2:

nums1 = [1, 2] nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5

由于两个vector是有序的,我们可以是用来类似归并排序的方法将两个vector进行结合,注意由于只需要得到中位数,故没有必要添加所有数据,到达中位数即可。

class Solution {
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        vector<int> C;
        int i, j;
        int mid = (m+n) / 2 + 1;
        for(i=0, j=0;i<m && j<n;){
            if(A[i] > B[j]){
                C.push_back(B[j++]);
            }
            else{
                C.push_back(A[i++]);
            }
            if(C.size() == mid){
                break;
            }
        }
        while(C.size() != mid){
            if(i < m)
                C.push_back(A[i++]);
            if(j < n)
                C.push_back(B[j++]);
        }
        if ((m+n) % 2 == 0)
            return (C[C.size()-1] + C[C.size()-2]) / 2.0;
        return *(C.end()-1);
    }
};

3.无重复字符的最长子串

给定一个字符串,找出不含有重复字符的最长子串的长度。

示例 1:
输入: “abcabcbb” 输出: 3 解释: 无重复字符的最长子串是 “abc”,其长度为 3。 示例 2:

输入: “bbbbb” 输出: 1 解释: 无重复字符的最长子串是 “b”,其长度为 1。 示例 3:

输入: “pwwkew” 输出: 3 解释: 无重复字符的最长子串是 “wke”,其长度为 3。
请注意,答案必须是一个子串,”pwke” 是一个子序列 而不是子串。

这道题也是建立一个map,然后使用left去储存当重复字符出现时最左侧的索引,并去掉重复元素的重复个数。很简单有效的思路,map的key值是可以重复出现的。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int left = 0, maxlen = 0;
        unordered_map<char, int> charmap;
        if(s.length() == 0) return 0;
        for(int i=0; i < s.length();i++){
            if(charmap.find(s[i]) != charmap.end()){
                left = max(left, charmap[s[i]] + 1);
            }
            maxlen = max(maxlen, i-left+1);
            charmap[s[i]] = i;
        }
        return maxlen;
    }
};

4.两数相加

给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8 原因:342 + 465 = 807

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
        //进位
        int carry = 0;
        ListNode* head = new ListNode(0);
        ListNode* pre = head;
        while(l1 != NULL || l2 != NULL || carry!=0){  //为null相当于零,但不能同时为null
            int sum = (l1 == NULL ? 0:l1->val) + (l2 == NULL ? 0:l2->val) + carry;
            ListNode* cur = new ListNode(sum%10);  //当前节点的值为个位数
            carry = sum / 10;
            pre->next = cur;
            pre = cur;   // 把pre从head指向cur

            l1 = (l1==NULL ? l1 : l1->next);   //寻找下一个节点
            l2 = (l2==NULL ? l2 : l2->next);
        }
        return head->next;
    }
};

声明

以上代码均参考于牛客网并在牛客网测试成功。参考了各位大佬的思路整理而成,希望大家一起学习~

猜你喜欢

转载自blog.csdn.net/weixin_41576121/article/details/82721567
今日推荐