LeetCode HOT 100 --- 2021/7/29

两数相加

在这里插入图片描述
分析:
  十进制的加法。
代码:

/**
 * 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* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *head = nullptr, *tail = nullptr;
        int carry = 0;
        while (l1 || l2) {
            int n1 = l1 ? l1->val: 0;
            int n2 = l2 ? l2->val: 0;
            int sum = n1 + n2 + carry;
            if (!head) {
                head = tail = new ListNode(sum % 10);
            } else {
                tail->next = new ListNode(sum % 10);
                tail = tail->next;
            }
            carry = sum / 10;
            if (l1) {
                l1 = l1->next;
            }
            if (l2) {
                l2 = l2->next;
            }
        }
        if (carry > 0) {
            tail->next = new ListNode(carry);
        }
        return head;
    }
};

无重复字符的最长子串

剑指 Offer 48. 最长不含重复字符的子字符串

最长回文子串

在这里插入图片描述
方法一:
  暴力求解:超时。
代码:

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        int maxLen = 0;
        string res = "";
        for(int i = 0; i < n; i++) {
            for(int j = 0; j <= n - i; j++) {
                string sub = s.substr(i, j);
                string temp = sub;
                reverse(sub.begin(), sub.end());
                if(temp == sub && temp.size() > maxLen) {
                    maxLen = temp.size();
                    res = temp;
                }
            }
        }
        return res;
    }
};

方法二:
  动态规划:设dp[i][j]为true表示s[i…j]是一个回文串。
  边界条件:

dp[i][i] = true;
if s[i] == s[i + 1] then dp[i][i + 1] = true;

  状态转移方程:

if dp[i + 1][j - 1] && s[i] == s[j] then dp[i][j] = true;

代码:

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(n, false));
        string res = "";
        res += s[0];
        int maxLen = 1;
        //边界条件
        for(int i = 0; i < n; i++) {
            dp[i][i] = true;
            if(i + 1 < n && s[i] == s[i + 1]) {
                dp[i][i + 1] = true;
                maxLen = 2;
                res = s.substr(i, 2);
            }
        }
        //转移方程,注意这里要从中心向外扩展
        for(int i = n - 1; i >= 0; i--) {
            for(int j = i + 2; j < n; j++) {
                if(dp[i + 1][j - 1] && (s[i] == s[j])) {
                    dp[i][j] = true;
                    if(j - i + 1 > maxLen) {
                        res = s.substr(i, j - i + 1);;
                        maxLen = j - i + 1;
                    }
                }   
            }
        }
        return res;
    }
};

盛最多水的容器

在这里插入图片描述
分析:
  依次枚举,枚举过程中保存最大值。设置两个指针,初始时分别指向两端。如果当前height[l] <= height[r],那么我们只能移动较小的左指针,因为容器体积 = (r - l) * min(height[l], height[r]),如果移动右指针,最小值可能不会变(也可能增加),距离减小,体积也会减小,所以我们移动左指针。同理,当height[l] > height[r]时移动右指针。
代码:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int l = 0, r = height.size() - 1;
        int ans = 0;
        while(l < r) {
            int x = (r - l) * min(height[l], height[r]);
            ans = max(ans, x);
            if(height[l] <= height[r]) {
                l++;
            }else {
                r--;
            }
        }
        return ans;
    }
};

三数之和

在这里插入图片描述
分析:
  首先将数组进行排序。枚举第一个数,随后在其右侧区间利用二分法查找剩余的两个数,注意会有重复。
代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        int n = nums.size();
        if(n < 3) {
            return {};
        }
        sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        for(int i = 0; i < n; i++) {
            if(nums[i] > 0) {
                continue;
            }
            if(i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int left = i + 1, right = n - 1;
            while(left < right) {
                if(nums[left] + nums[right] > -nums[i]) {
                    right--;
                }else if(nums[left] + nums[right] < -nums[i]) {
                    left++;
                }else {
                    res.push_back({nums[i], nums[left], nums[right]});
                    left++;
                    right--;
                    while(left < right && nums[left] == nums[left - 1]) {
                        left++;
                    }
                    while(left < right && nums[right] == nums[right + 1]) {
                        right--;
                    }
                }
            }
        }
        return res;
    }
};

下一个排列

在这里插入图片描述
方法一:
  利用c++封装好的next_permutation。
代码:

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        if(next_permutation(nums.begin(), nums.end())) {
            //do nothing
        }else {
            sort(nums.begin(), nums.end());
        }
    }
};

方法二:
  参考官方题解:
在这里插入图片描述
代码:

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int i = nums.size() - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.size() - 1;
            while (j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            swap(nums[i], nums[j]);
        }
        reverse(nums.begin() + i + 1, nums.end());
    }
};

搜索旋转排序数组

在这里插入图片描述
分析:
  对一个数组,其左边部分是升序的,右边部分也是升序的,但是总体不一定升序,并且左半部分比右半部分大。比如9, 11, 12, 13, 1, 2, 3。对于此种“伪有序”的数组,也可以使用二分法查找,具体方法如下:
  初始令l和r指向数组两端,如果当前nums[mid] == target,则返回;如果nums[0] <= nums[mid],说明mid当前在左半边,进一步如果nums[0] <= target && target <= nums[mid],则说明target在左半边的某个位置,执行r = mid - 1,否则l = mid + 1;如果nums[0] > nums[mid],说明mid在右半部分的升序序列里面,进一步如果nums[mid] <= target && target <= nums[n],说明target还在mid左边,执行r = mid - 1,否则执行l = mid + 1。
代码:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if (nums.size() == 0) {
            return -1;
        }
        int n = nums.size() - 1;
        if (n == 0) {
            return nums[0] == target ? 0 : -1;
        }
        int l = 0, r = n;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            if (nums[0] <= nums[mid]) {
                // 左半边有序
                if (nums[0] <= target && target <= nums[mid]) {
                // target的值在左半边
                    r = mid - 1;
                }
                else {
                    l = mid + 1;
                }
            }
            else {
                // 右半边有序
                if (nums[mid] <= target && target <= nums[n]) {
                // target的值在右半边
                    l = mid + 1;
                }
                else {
                    r = mid - 1;
                }
            }
        }
        return -1;
    }
};
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cyril_KI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值