算法闭关修炼百题计划(四)

仅供个人复习

1.两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

cpp 复制代码
/*
因为两个链表都是逆序,相当于个位数在最前面,所以可以直接相加,多余的十位数、百位数 用 temp 记录下来,加到下一个节点
*/
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        //构建新链表的头节点和尾节点
        ListNode* head = nullptr;
        ListNode* tail = nullptr;
        int tmp = 0; //相加的进位,比如7+8=15,tmp=1

        while (l1 != nullptr || l2 != nullptr) {
            int val1 = l1 != nullptr ? l1->val : 0; // l1不为空,取节点的值,为空则取0
            int val2 = l2 != nullptr ? l2->val : 0;
            int sum = val1 + val2 + tmp;

            // 往相加的链表后拼接节点
            if (head == nullptr) {
                head = new ListNode(sum % 10);
                tail = head;
            } else {
                tail->next = new ListNode(sum % 10);
                tail = tail->next;
            }

            tmp = sum / 10; //除了个位数,剩下的是进位,放入tmp
            if (l1 != nullptr) l1 = l1->next;
            if (l2 != nullptr) l2 = l2->next;
        }

        //最后如果 tmp ≠ 0,说明还有进位,需要一个节点存放
        if (tmp > 0) tail->next = new ListNode(tmp);

        return head;
    }
};

2.寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

二分法,注意mid+1可能越界

cpp 复制代码
class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int L = -1, R = nums.size();
        if(nums.size() == 1) return 0;
        while(L + 1 != R){
            int mid = (L + R) / 2;
            if(mid == nums.size() - 1){
                R = nums.size() - 1;
                break;
            }
            if(nums[mid] > nums[mid + 1]) R = mid;
            else L = mid;
        }
        return R;
    }
};

6.岛屿的最大面积

cpp 复制代码
class Solution {
public:
    int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1};
    int count;
    void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y){
        for(int i = 0; i < 4; i ++){
            int nextx = x + dir[i][0];
            int nexty = y + dir[i][1];
            if(nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            if(!visited[nextx][nexty] && grid[nextx][nexty] == 1){
                visited[nextx][nexty] = true;
                count++;
                dfs(grid, visited, nextx, nexty);
            }
        }

    }
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int res = 0;
        vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false));
        for(int i = 0; i < grid.size(); i ++){
            for(int j = 0; j < grid[0].size(); j ++){
                if(grid[i][j] == 1 && !visited[i][j]){
                    count = 1;//每个岛屿重置count
                    visited[i][j] = true;
                    dfs(grid, visited, i, j);
                    res = max(res, count);
                }
            }
        }
        return res;
    }

};

3.最大数

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

cpp 复制代码
class Solution {
public:
    string largestNumber(vector<int>& nums) {
        vector<string> str;
        for(auto i : nums){
            str.push_back(to_string(i));
        }
        auto cmp = [](string left, string right){return left + right > right + left;};
        sort(str.begin(), str.end(), cmp);
        string ans = "";
        for(auto c : str){
            ans += c;
        }
        if(ans[0] == '0') return "0";
        return ans;

    }
};

4.会议室

给你一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间 intervals[i] = [starti, endi] ,返回 所需会议室的最小数量 。

输入:intervals = [[0,30],[5,10],[15,20]]

输出:2

可以把他理解为上车下车问题

同时在车上最多人数就是需要的会议室数量

挺巧的这个做法

cpp 复制代码
class Solution {
public:
    int minMeetingRooms(vector<vector<int>>& intervals) {
        map<int, int> umap;
        for(auto it : intervals){
            umap[it[0]]++;
            umap[it[1]]--;
        }
        int ans = 0, cnt = 0;
        for(auto itt : umap){
            cnt += itt.second;
            ans = max(ans, cnt);
        }
        return ans;
    }
};

用map而不是unordered_map,因为键值对在map中是有序的,即元素按照键的升序排列。用他才能用上车下车的写法。

5.最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

cpp 复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> set(nums.begin(), nums.end());
        int res = 0;
        for(int num : set){
            if(set.find(num - 1) != set.end()) continue;//不是第一个就跳过,因为我们要找第一个
            int curNum = num;
            int curLen = 1;
            while(set.find(curNum + 1) != set.end()){
                curNum += 1;
                curLen += 1;
            }
            res = max(res, curLen);
        }
        return res;
    }
};

6.寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

输入:nums1 = [1,3], nums2 = [2]

输出:2.00000

解释:合并数组 = [1,2,3] ,中位数 2

碎碎念:除了学然后背还能怎样呢?这篇已经接近终章了,最后应该到不了一百题,剩余不多的时间给自己复习吧,反正都是背,学了没背住就太亏了。

有难度,但可能是因为题解看多了,看懂并不难。。。(笑

简单点来说,要找第k小的,咱每次排除k / 2个元素,两个有序数组,分别找他们的第k/2 - 1个数,比较,较小的那个数所在的数字的第0~k/2-1个数都不可能是答案,所以就排除掉了,这个数字的index++,另一个数组的index怎么办?

首先明确,咱不断比较的是有可能存在答案的数组的前k/2 - 1,没被排除的数组,从下标0开始都有可能,他们的index,仍然是+ k/2 - 1,从index开始的

其次,注意边界问题,假如数组顺序是完全无缝衔接的,那么就会遇到越界问题,越界的时候说明,中位数在另一个数组中,直接加上剩余的k即可

cpp 复制代码
class Solution {
public:
    int getKthElement(vector<int>& nums1, vector<int>& nums2, int k){
        int m = nums1.size();
        int n = nums2.size();
        int index1 = 0, index2 = 0;
        while(true){
            if(index1 == m) return nums2[index2 + k - 1];
            if(index2 == n) return nums1[index1 + k - 1];
            if(k == 1) return min(nums1[index1], nums2[index2]);
            int newIndex1 = min(index1 + k/2 - 1, m - 1);//防止越界
            int newIndex2 = min(index2 + k/2 - 1, n - 1);
            int pivot1 = nums1[newIndex1];
            int pivot2 = nums2[newIndex2];
            if(pivot1 <= pivot2){
                k -= newIndex1 - index1 + 1;
                index1 = newIndex1 + 1;
            }
            else{
                k -= newIndex2 - index2 + 1;
                index2 = newIndex2 + 1;
            }
        }

    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int totalLength = nums1.size() + nums2.size();
        if(totalLength % 2 == 1) return getKthElement(nums1, nums2, (totalLength + 1) / 2);
        else{
            return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
        }

    }
};
相关推荐
Gorgous—l22 分钟前
数据结构算法学习:LeetCode热题100-动态规划篇(下)(单词拆分、最长递增子序列、乘积最大子数组、分割等和子集、最长有效括号)
数据结构·学习·算法
北京地铁1号线1 小时前
2.3 相似度算法详解:Cosine Similarity 与 Euclidean Distance
算法·余弦相似度
圣保罗的大教堂1 小时前
leetcode 1895. 最大的幻方 中等
leetcode
Remember_9931 小时前
【LeetCode精选算法】滑动窗口专题一
java·数据结构·算法·leetcode·哈希算法
Lueeee.1 小时前
v4l2驱动开发
数据结构·驱动开发·b树
小饼干超人2 小时前
详解向量数据库中的PQ算法(Product Quantization)
人工智能·算法·机器学习
你撅嘴真丑2 小时前
第四章 函数与递归
算法·uva
漫随流水2 小时前
leetcode回溯算法(77.组合)
数据结构·算法·leetcode·回溯算法
玄冥剑尊3 小时前
动态规划入门
算法·动态规划·代理模式
mjhcsp3 小时前
P14987 全等(mjhcsp)
算法·题解·洛谷