国庆七天乐LeetCode算法14天集训营题解(1~7天)

Posted 沉迷单车的追风少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了国庆七天乐LeetCode算法14天集训营题解(1~7天)相关的知识,希望对你有一定的参考价值。

国庆正好空闲,想着好久没有刷题了(太懒),应该push自己一点,那就看看简单的算法集训营吧~

在数学和计算机科学之中,算法是一个被定义好的、计算机可施行之指示的有限步骤或次序,常用于计算、数据处理和自动推理。作为一个有效方法,算法被用于计算函数,它包含了一系列定义清晰的指令,并可于有限的时间及空间内清楚的表述出来。 

目录

第一天:二分查找

LeetCode704.二分查找

 LeetCode278.第一个错误的版本

LeetCode35.搜索插入位置

第二天:双指针

LeetCode977.有序数组的平方

LeetCode.189旋转数组

第三天:双指针

LeetCode283.移动零

LeetCode167.两数之和II-输入有序数组

第四天:双指针

LeetCode344.反转字符串

LeetCode557.反转字符串中的单词III

第五天:双指针

LeetCode876.链表的中间结点

 LeetCode19.删除链表的倒数第N个结点

第六天:滑动窗口

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

LeetCode567.字符串的排列

第七天:广度优先搜索/深度优先搜索

LeetCode733.图像渲染

LeetCode695.岛屿的最大面积


第一天:二分查找

LeetCode704.二分查找

 直接暴力也可以过:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int ans = -1;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] == target) {
                return i;
            }
        }
        return ans;
    }
};

 真正的二分:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0; 
        int right = nums.size() - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }
};

 LeetCode278.第一个错误的版本

暴力直接爆掉,拙劣

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        // int ans = -1;
        for (int i = 1; i <= n; i++) {
            if (isBadVersion(i)) {
                return i;
            }
        }
        return -1;
    }
};

还是老老实实二分法:

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        long long int left = 1;
        long long int right = n;
        while (left < right) {
            long long int mid = (left + right) /2;
            if (isBadVersion(mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return right;
    }
};

 

LeetCode35.搜索插入位置

暴力瞎鸡巴搞:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int pos = nums.size();
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] >= target){
                return i;
            }
        }
        return pos;
    }
};

有B格的二分法,居然运行时间更慢,我佛了。。。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] < target){
                left = mid + 1;
            } else {
                return mid;
            }
        }
        return right + 1;
    }
};

第二天:双指针

LeetCode977.有序数组的平方

 瞎鸡巴写,也能过……

class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        for(int i=0;i<A.size();i++){
            A[i]*=A[i];
        }
        sort(A.begin(),A.end());
        return A;
    }
};

卧槽,原来我一年前做过啊。。

哥的青春被狗吃了

双指针就是利用递增数组的性质,依次比较加入到数组当中,没啥意思,不写了,就是任性

LeetCode.189旋转数组

 我记得华为机试经常出现这一题,简单一点的思路就是经过三次旋转就能搞定

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        k %= nums.size();
        reverse(nums.begin(), nums.end());
        reverse(nums.begin() + k, nums.end());
        reverse(nums.begin(), nums.begin() + k);
    }
};

好像也是剑指offer里面的原题,好像这样交换的时间复杂度最低了,O(n),那就先过吧,搞什么双指针,再见。

第三天:双指针

LeetCode283.移动零

 忘记是不是剑指offer上面的了……这样做的时间复杂度也是O(N)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        // 双指针,一个指针用于遍历数组,一个指针用于处理非0
        int j = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] != 0) {
                nums[j++] = nums[i];
            }
        }
        while(j < nums.size()) {
            nums[j++] = 0;
        }
    }
};

LeetCode167.两数之和II-输入有序数组

 为啥都是我做过的呀。。。。没意思

最好的方法就是定义一个双指针去寻找,这样的时间复杂度最低了。

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        vector<int> ans;    
        int left = 0; 
        int right = numbers.size() - 1;
        while (left < right) {
            if (numbers[left] + numbers[right] == target) {
                ans.push_back(++left);
                ans.push_back(++right);
                return ans;
            } else if (numbers[left] + numbers[right] < target) {
                left++;
            } else {
                right--;
            }
        }
        return ans;
    }
};

第四天:双指针

LeetCode344.反转字符串

 之前写过一行代码就解LeetCode,可以没啥人看,可恶啊……都不喜欢玩。。。

class Solution {
public:
    void reverseString(vector<char>& s) {
        reverse(s.begin(),s.end());
    }
};

双指针的解法就不搞了,下一个

LeetCode557.反转字符串中的单词III

 看代码,easy,很符合那种水一点的笔试面试,就是想一分钟内A掉还是蛮考验人的。。。

class Solution {
public:
    string reverseWords(string s) {
        // 双指针,j用于找后一个空格,i用于前一个空格
        int i = 0; 
        int j = 0;
        while (j < s.size()) {
            while (s[j] != ' ' && j < s.size())
                j++;
            reverse(s.begin() + i, s.begin() + j);
            i = ++j;
        }
        return s;
    }
};

第五天:双指针

LeetCode876.链表的中间结点

最经典的快慢指针题目,过瘾啊!

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        auto fast = head;
        auto slow = head;
        while (fast != nullptr && fast->next != nullptr) {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
};

还是我刚开始刷题时候学会的,哎,那时候真的学了好多东西呀

 LeetCode19.删除链表的倒数第N个结点

 卧槽,这也是我刚学数据结构的时候刷的题啊!

经典快慢指针,快指针先走n步而已。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if(head == nullptr || head->next == nullptr)
            return nullptr;
        ListNode* dummy = new ListNode(-1);
        dummy->next = head;
        ListNode* fast, *slow;
        fast = slow = head;
        while (n) {
            fast = fast->next;
            n--;
        }
        // 当n等于链表长度的时候,这种情况应当特殊处理!
        if(!fast)
            return head->next;
        while(fast->next!=nullptr&&fast!=nullptr){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return dummy->next;
    }
};

第六天:滑动窗口

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

有意思的题目终于来了……

很经典的滑动窗口,因为unordered_set中底层是哈希表,count平均时间复杂度是O(1),而find的时间复杂度为O(logN);但是set底层是红黑树,count时间复杂度就是O(logN)了。所以用哈希表代替数组,表示滑动窗口。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if (s.empty()) {
            return 0;
        }
        int left = 0;
        int ans = 0;
        unordered_set<char> hash;
        for (int right = 0; right < s.size(); right++) {
            // 如果窗口右侧字符的出现过,从左边缩小窗口
            while (hash.count(s[right])) {
                hash.erase(s[left]);
                left ++;
            }
            // 继续从右侧扩大窗口
            hash.insert(s[right]);
            // 时刻维护最大长度
            ans = max(ans, right - left + 1);
        }
        return ans;
    }
};

LeetCode567.字符串的排列

做到目前为止终于碰到我没有做过的题目了,哈哈哈哈搞起来冲

这道题的排列并没有强调顺序,因此我们对于顺序不再关注。

可是怎样做到不关注顺序呢?一种方法是排序后比较。这样的时间复杂度比较高。

另一种好的方法是维护一个哈希表,这个哈希表中存放着每个字符出现的次数,每一次滑动窗口的时候记得改变。

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        if (s2.empty() || (s1.size() > s2.size())) {
            return false;
        }
        // 记录字符串中出现的次数
        vector<int> h1(26, 0);
        vector<int> h2(26, 0);
        for (int i = 0; i < s1.size(); i++) {
            h1[s1[i] - 'a']++;
            h2[s2[i] - 'a']++;
        }
        for (int i = s1.size(); i < s2.size(); i++) {
            if (h1 == h2) {
                return true;
            }
            // 匹配不成功窗口向右滑动
            h2[s2[i - s1.size()] - 'a']--;
            h2[s2[i] - 'a']++;
        }
        return h1 == h2;
    }
};

第七天:广度优先搜索/深度优先搜索

LeetCode733.图像渲染

 这道题和200题经典岛屿是一模一样的,经典,后面可以考虑写一个专辑来介绍

class Solution {
public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
        if (image.empty() || image.size() == 0 || image[0].size() == 0) {
            return image;
        }
        if (image[sr][sc] == newColor) {    
            return image;
        }
        dfs(image, sr, sc, newColor, image[sr][sc]);
        return image;
    }
    void dfs(vector<vector<int>>& image, int i, int j, int newColor, int oldColor) {
        // 先写终止条件
        if (i < 0 || j < 0 || i >= image.size() || j >= image[0].size() 
            || image[i][j] != oldColor) {
            return;
        }
        // 再标记为已经搜索过
        image[i][j] = newColor;
        // 继续下一次搜索
        dfs(image, i - 1, j, newColor, oldColor);
        dfs(image, i + 1, j, newColor, oldColor);
        dfs(image, i, j + 1, newColor, oldColor);
        dfs(image, i, j - 1, newColor, oldColor);
    }
};

LeetCode695.岛屿的最大面积

 好家伙,看上去像是DFS的模板题,冲~

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0;
        for (int i = 0; i < grid.size(); i++) {
            for (int j = 0; j < grid[0].size(); j++) {
                if (grid[i][j] == 1) {
                    ans = max(dfs(grid, i, j), ans);
                }
            }
        }
        return ans;
    }
    int dfs(vector<vector<int>>& grid, int i, int j) {
        if (i < 0 || j < 0|| i >= grid.size() || j >= grid[0].size()
            || grid[i][j] == 0) {
            return 0;
        }
        grid[i][j] = 0;
        int count = 1;
        count += dfs(grid, i - 1, j);
        count += dfs(grid, i + 1, j);
        count += dfs(grid, i, j - 1);
        count += dfs(grid, i, j + 1);
        return count;
    }
};

国庆七天的题就写完了,爽不爽?开始没啥意思,因为大多数都是我写过的题目,后面的题目学到了不少东西。

很久很久没有写LeetCode系列了,看到群里有的人一道题就发一篇blog,解析也就几十个字。照他这样,我一天一篇能写到明年哈哈哈……

以上是关于国庆七天乐LeetCode算法14天集训营题解(1~7天)的主要内容,如果未能解决你的问题,请参考以下文章

10.3校内测试国庆七天乐!DP+组合数学/容斥spfa多起点多终点+二进制分类

国庆七天乐——第三天

国庆七天乐——第二天

国庆七天乐——第五天

国庆七天乐——第一天

国庆七天乐