zoukankan      html  css  js  c++  java
  • 【leetcode】腾讯精选练习 50 题(更新中)

    2. 两数相加

    https://leetcode-cn.com/problems/add-two-numbers/

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

    题目思路

    总共三个数需要相加,l1取的节点的值,l2取的节点的值,以及上一轮的进位。
    然后算得给下一轮的进位,并将当前值只保留个位。
    注意:最后如果只剩一个进位,而l1和l2没有取到值,这时候也是要输出一个节点的。
    时间和空间复杂度均为O(max(m,n))。

    代码

    /**
     * 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) {
            int save = 0;
            ListNode* rst = new ListNode(0);
            ListNode* cur = rst;
            
            do {
                int left = 0;
                int right = 0;
                int all = 0;
                if (l1 != nullptr) {
                    left = l1->val;
                    l1 = l1->next;
                }
                if (l2 != nullptr) {
                    right = l2->val;
                    l2 = l2->next;
                }
                all = left + right + save;
                // cout << all << endl;
                save = all / 10;
                all = all % 10;
                
                ListNode* temp = new ListNode(all);
                cur->next = temp;
                cur = cur->next;
            } while (l1 != nullptr || l2 != nullptr);
    
            if (save != 0) {
                ListNode* temp = new ListNode(save);
                cur->next = temp;
                cur = cur->next;
            }
    
            return rst->next;
        }
    };
    

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

    https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

    给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
    进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

    题目思路

    首先是判断中位数的位置,总共为奇数个的话,是最中间的一个数,偶数的话,是最中间的两个数求平均。
    偶数个的时候,划分两个数组,左边总共(m+n)/2个数,奇数个的时候,左边总共(m+n+1)/2个数(中位数人为定义放左边)。统一奇偶写法为(m+n+1)/2。
    最终需要确定划分的位置即可,为了方便处理边界值,将较短的一个数组设为nums1,则nums1的划分确定,根据上述,nums2的划分也随之确定。
    最终划分确定需要满足交叉判断条件,nums1[i-1] <= nums2[j] && nums2[j-1] <= nums1[i],注意考虑边界条件,具体在代码中有体现。
    注意:二分查找中当看到left = i时,要考虑上取整,left = i-1时,不用上取整。

    代码

    class Solution {
    public:
        double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
            // 保持nums1更短
            if (nums1.size() > nums2.size()) {
                return findMedianSortedArrays(nums2, nums1);
            }
    
            int m = nums1.size();
            int n = nums2.size();
            // 偶数 (m+n)/2 == (m+n+1)/2 
            // 奇数 (m+n+1)/2 中位数在左边
            int leftTotal = (m + n + 1) / 2;
    
            // 二分查找
            // 交叉判断条件:
            // nums1[i-1] <= nums2[j] && nums2[j-1] <= nums1[i]
            int left = 0;
            int right = m;
            while (left < right) { // 最终left == right退出,只有一个值,因此交叉判断条件取一个即可
                int i = left + (right - left + 1) / 2;
                int j = leftTotal - i;
                if (nums1[i-1] > nums2[j]) { // i-1不会溢出,因为有上取整,i != 0
                    right = i - 1;
                } else {
                    // 特殊情况:[left(i), right(i+1)], 区间无法缩小
                    // 因此i定义的时候,需要上取整(+1)
                    left = i;
                }
            }
    
            int i = left;
            int j = leftTotal - i;
            int leftNums1 = (i == 0 ? INT_MIN : nums1[i-1]);
            int rightNums1 = (i == m ? INT_MAX : nums1[i]);
            int leftNums2 = (j == 0 ? INT_MIN : nums2[j-1]);
            int rightNums2 = (j == n ? INT_MAX : nums2[j]);
    
            if ((m + n) % 2 == 1) {
                return max(leftNums1, leftNums2);
            } else {
                return (max(leftNums1, leftNums2) + min(rightNums1, rightNums2)) / 2.0;
            }     
        }
    };
    

    5. 最长回文子串

    https://leetcode-cn.com/problems/longest-palindromic-substring/

    给你一个字符串 s,找到 s 中最长的回文子串。

    解题思路

    中心扩散法:遍历字符,以当前字符向两边扩散,找到最长的回文串。时间复杂度O(n^2),空间复杂度O(1)。枚举子串个数O(n)。
    动态规划法(空间换时间):保存状态dp[i][j],即从下标i到下标j的子串是否为回文。时间复杂度O(n2),空间复杂度O(n2)。枚举子串个数O(n^2),耗时更长。
    Manacher算法:结合中心扩散法和动态规划,时间复杂度O(n),空间复杂度O(n)。(面试不用掌握这个方法)

    当在位置 i 开始进行中心拓展时,我们可以先找到 i 关于 j 的对称点 2 * j - i。
    那么如果点 2 * j - i 的臂长等于 n,我们就可以知道,点 i 的臂长至少为 min(j + length - i, n)。
    那么我们就可以直接跳过 i 到 i + min(j + length - i, n) 这部分,从 i + min(j + length - i, n) + 1 开始拓展。

    统一奇偶字符串的技巧:在字符中间插入#。

    代码

    class Solution {
    public:
        int palindromeLen(string s, int left, int right) {
            while (left >= 0 && right < s.size() && s[left] == s[right]) {
                left -= 1;
                right += 1;
            }
            return right-left-1;
        }
        string longestPalindrome(string s) {
            int max_index = 0;
            int max_len = 0;
            string ret;
            for (int i = 0; i < s.size(); i++) {
                int temp_len = max(palindromeLen(s, i, i), palindromeLen(s, i, i+1));
                if (temp_len > max_len) {
                    max_len = temp_len;
                    max_index = i;
                }
            }
            if (max_len % 2 == 0) {
                ret = s.substr(max_index+1 - max_len/2, max_len);
            } else {
                ret = s.substr(max_index - max_len/2, max_len);
            }
            return ret;
        }
    };
    

    7. 整数反转

    https://leetcode-cn.com/problems/reverse-integer/

    给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

    注意:
    假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231,  231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

    解题思路

    题目比较简单,不过要注意判断,避免溢出。
    时间复杂度:O(log(x))。
    空间复杂度:O(1)。

    代码

    class Solution {
    public:
        int reverse(int x) {
            int rev = 0;
            while(x != 0) {
                int temp = x % 10;
                x /= 10;
                if (rev > INT_MAX/10 || (rev == INT_MAX / 10 && temp > 7)) return 0;
                if (rev < INT_MIN/10 || (rev == INT_MIN / 10 && temp < -8)) return 0;
                rev = rev * 10 + temp;
            }
            return rev;
        }
    };
    

    8. 字符串转换整数 (atoi)

    https://leetcode-cn.com/problems/string-to-integer-atoi/

    请你来实现一个 atoi 函数,使其能将字符串转换成整数。
    首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
    如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
    假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
    该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
    假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
    在任何情况下,若函数不能进行有效的转换时,请返回 0。

    注意:
    本题中的空白字符只包括空格字符 ' ' 。
    假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31,  2^31 − 1]。如果数值超过这个范围,请返回  2^31 − 1 或 −2^31。

    解题思路

    代码

    class Solution {
    public:
        int myAtoi(string s) {
            int ret = 0;
            int start = true;
            int flag = 1;
            for (int i = 0; i < s.size(); i++) {
                if (start && s[i] == ' ')
                    continue;
                if (start && (s[i] == '-' || s[i] == '+')) {
                    if (s[i] == '-')
                        flag = -1;
                    start = false;
                    continue;
                }
                if (s[i] >= '0' && s[i] <= '9') {
                    start = false;
                    int temp = flag * (s[i]-'0');
                    if (ret > INT_MAX/10 || (ret == INT_MAX/10 && temp > 7)) return INT_MAX;
                    if (ret < INT_MIN/10 || (ret == INT_MIN/10 && temp < -8)) return INT_MIN;
                    ret = ret*10 + temp;
                } else {
                    break;
                }
            }
            return ret;
        }
    };
    

    9. 回文数

    https://leetcode-cn.com/problems/palindrome-number/

    判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
    你能不将整数转为字符串来解决这个问题吗?

    解题思路

    负数不满足条件,先过滤掉。然后反转数字,判断是否相等。(注意可能溢出)

    代码

    class Solution {
    public:
        bool isPalindrome(int x) {
            if (x < 0) {
                return false;
            }
            
            int reverse = 0;
            int x_cp = x;
            while (x != 0) {
                int temp = x % 10;
                x /= 10;
                if (reverse > INT_MAX/10 || ((reverse == INT_MAX/10) && temp > 7)) return false;
                reverse = reverse * 10 + temp;
            }
            if (reverse == x_cp) {
                return true;
            }
            return false;
        }
    };
    
  • 相关阅读:
    C# WinForm API 改进单实例运行
    CF1310D Tourism [随机化]
    CF1311E Construct the Binary Tree
    [IOI2018] werewolf 狼人 [kruskal重构树+主席树]
    #6029. 「雅礼集训 2017 Day1」市场 [线段树]
    P5840 [COCI2015]Divljak [AC自动机,链并]
    CF547E Mike and Friends [AC自动机,离线树状数组]
    P5112 FZOUTSY
    CF 150E Freezing with Style [长链剖分,线段树]
    CF1230E Kamil and Making a Stream
  • 原文地址:https://www.cnblogs.com/yanqiang/p/14264966.html
Copyright © 2011-2022 走看看