LeetCode 1 ~ 10

本文介绍了LeetCode中几道典型的算法题,包括使用哈希表寻找两数之和、链表相加、无重复字符最长子串、寻找中位数、最长回文子串、Z字形变换、整数反转、字符串转换整数、回文数判断以及正则表达式匹配。每道题都详细解析了算法思路,涉及哈希表、双指针、链表操作等数据结构和算法技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode 1. 两数之和

使用哈希表记录每个遍历过的数和对应的位置,使用目标值减去当前遍历到的数值得到想要的值r,如果哈希表中已经存在这个值r,那么就返回r对应的下表和当前遍历到的值得下标。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hash;
        for(int i = 0; i < nums.size(); i ++ ) {
            int r = target - nums[i];
            if(hash.count(r)) return {hash[r], i};
            hash[nums[i]] = i;
        }
        return {};
    }
};

LeetCode 2. 两数相加

链表模拟大数相加的过程,可以类比高精度加法的做法。
做法如下:
1.同时从头开始遍历两个链表的值,将两个值相加存进中间变量t,然后分别指向next节点,新链表的下个节点赋值为(t % 10),t /= 10进位。
2.如果遍历完两个链表后,t != 0 ,那么就再创建一个新节点并赋值为 t

/**
 * 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) {
        auto dummy = new ListNode(-1), cur = dummy;
        int t = 0;
        while(l1 || l2 || t){
            if(l1) t += l1->val, l1 = l1->next;
            if(l2) t += l2->val, l2 = l2->next;
            cur = cur -> next = new ListNode(t % 10);
            t /= 10;
        }
        return dummy -> next;
    }
};

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

双指针算法。
使用一个哈希表维护当前找到的字符串区间 [i, j] 中字母的个数。
如果出现重复字符,那么指针 i 向后移动一位,并且哈希表中这个字符的出现次数减一,直到没有重复字符为止,使用了一个while循环实现
如果没有重复字符,那么指针 j 向后移动一位,同时哈希表中对应的字符出现次数加一
在这个过程中使用res记录字串长度的最大值。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> hash;
        int res = 0;
        for (int i = 0, j = 0; j < s.size(); j ++ )
        {
            hash[s[j]] ++ ;
            while (hash[s[j]] > 1) hash[s[i ++ ]] -- ;
            res = max(res, j - i + 1);
        }
        return res;
    }
};

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

寻找两个正序数组的中位数,可以将它转换成寻找两个正序数组中的第k小数,只要能将寻找第k小数的问题能解决,我们需要寻找的中位数就是第(n+m)/2小数。

  1. 当一共有偶数个数时,找到第left = total / 2小和第right = total / 2 + 1小,结果是(left + right / 2.0)
  2. 当一共有奇数个数时,找到第total / 2 + 1小,即为结果
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int total = nums1.size() + nums2.size();
        if (total % 2 == 0) {
            int left = findKthNumber(nums1, 0, nums2, 0, total / 2);
            int right = findKthNumber(nums1, 0, nums2, 0, total / 2 + 1);
            return (left + right) / 2.0;
        }
        return findKthNumber(nums1, 0, nums2, 0, total / 2 + 1);
    }

    int findKthNumber(vector<int> &nums1, int i, vector<int> &nums2, int j, int k) {
        if (nums1.size() - i > nums2.size() - j) return findKthNumber(nums2, j, nums1, i, k);
        if (nums1.size() == i) return nums2[j + k - 1];
        if (k == 1) return min(nums1[i], nums2[j]);
        int si = min(i + k / 2, int(nums1.size())), sj = j + k / 2;
        if (nums1[si - 1] > nums2[sj - 1])
            return findKthNumber(nums1, i, nums2, j + k / 2, k - k / 2);
        else
            return findKthNumber(nums1, si, nums2, j, k - (si - i));
    }
};

LeetCode 5. 最长回文子串

暴力枚举
如果回文串长度是奇数,则回文串中心为 i,依次判断 s[i−k]==s[i+k],k=1,2,3,…
如果回文串长度是偶数,则回文串中心为 i, i+1,依次判断 s[i−k]==s[i+k−1],k=1,2,3,…
如果遇到不同字符,则我们就找到了以 i 为中心的回文串边界。

class Solution {
public:
    string longestPalindrome(string s) {
        string res;
        for(int i = 0; i < s.size(); i ++ ) {

			//奇数情况
            int l = i - 1, r = i + 1;
            while(l >= 0 && r < s.size() && s[l] == s[r]) l -- , r ++ ;
            if(res.size() < r - l - 1) res = s.substr(l + 1, r - l - 1);
			
			//偶数情况
            l = i, r = i + 1;
            while(l >= 0 && r < s.size() && s[l] == s[r]) l -- , r ++ ;
            if(res.size() < r - l - 1) res = s.substr(l + 1, r - l - 1);
        }
        return res;
    }
};

LeetCode 6. Z 字形变换

在行数等于3时,将字符串"PAYPALISHIRING"按”N”字形排列,如下所示:

P   A   H   N
A P L S I I G
Y   I   R

即:

0     4	   8
1  3  5  7  ..
2     6

而当行数是4的情况如下:

0     6       12
1   5 7    11 ..
2 4   8 10
3     9

可以发现这道题其实是个找数学规律的问题
从上面的例子中我们可以发现,对于行数是 n 的情况:
· 第一行和最后一行的是两个公差为 2(n−1)的等差数列,首项分别为0和n-1
·对于第 i (0<i<n−1),是两个公差为 2(n−1) 的等差数列交替排列,首项分别是 i 和 2n−i−2
按照这样的规律写代码即可

class Solution {
public:
    string convert(string s, int n) {
        string res;
        if(n == 1) return res;
        for(int i = 0; i < n; i ++ ) {
            if(i == 0 || i == n - 1) {
                for(int j = i; j < s.size(); j += 2 * n - 2)
                    res += s[j];
            } else {
                for(int j = i, k = 2 * n - 2 - i; j < s.size() || k < s.size(); j += 2 * n - 2, k += 2 * n - 2) {
                    if(j < s.size()) res += s[j];
                    if(k < s.size()) res += s[k];
                }
            }
        }

        return res;
    }
};

LeetCode 7. 整数反转

class Solution {
public:
    int reverse(int x) {
        long long r = 0;
        while(x)
        {
        	//后面的条件为判断x是否溢出,如果溢出则返回0
            if(r > 0 && r > (INT_MAX - x % 10) / 10) return 0;
            if(r < 0 && r < (INT_MIN - x % 10) / 10) return 0;
            r = r * 10 + x % 10;
            x /= 10;
        }
        return r;
    }
};

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

按照题目要求的做法模拟即可

class Solution {
public:
    int myAtoi(string str) {
    	//计算空格数量
        int k = 0;
        while(k < str.size() && str[k] == ' ') k ++ ;
        if(k == str.size()) return 0;
		
		//记录数值的正负符号
        int minus = 1;
        if(str[k] == '-') minus = -1, k ++ ;
        else if(str[k] == '+') k ++ ;

        int res = 0;
        while(k < str.size() && str[k] >= '0' && str[k] <= '9') {
            int x = str[k] - '0';
            //判断数值是否溢出
            if(minus > 0 && res > (INT_MAX - x) / 10) return INT_MAX;
            if(minus < 0 && -res < (INT_MIN + x) / 10) return INT_MIN;
            if(-res * 10 - x == INT_MIN) return INT_MIN;
            res = res * 10 + x;
            k ++ ;
            if(res > INT_MAX) break;
        }
		
		//乘上符号位
        res *= minus;
        if(res > INT_MAX) res = INT_MAX;
        if(res < INT_MIN) res = INT_MIN;

        return res;
    }
};

LeetCode 9. 回文数

使用字符串操作的函数进行判断即可

class Solution {
public:
    bool isPalindrome(int x) {
        if(x < 0) return 0;
        string s = to_string(x);
        return s == string(s.rbegin(), s.rend());
    }
};

LeetCode 10. 正则表达式匹配

设状态 f(i,j) 表示字符串 s 的前 i 个字符和字符串 p 的前 j 个字符能否匹配。这里假设 s 和 p 的下标均从 1 开始。初始时,f(0,0)=true。
转移 f(i,j)=f(i,j) or f(i−1,j−1),当 i>0s(i) == p(j) || p(j) == '.'
当 p(j) == ’ * ’ 时,若 j>=2,f(i,j)可以从 f(i,j−2)) 转移,表示丢弃这一次的 ’ * ’ 和它之前的那个字符;若 i>0 且 s(i) == p(j - 1),表示这个字符可以利用这个 ’ * ',则可以从 f(i−1,j)转移,表示利用 ’ * '。
初始状态 f(0,0)=true;循环枚举 i 从 0 到 n;j 从 1 到 m。因为 f(0,j) 有可能是有意义的,需要被转移更新。
最终答案为 f(n,m)。

引用
作者:wzc1995
链接:https://www.acwing.com/solution/content/557/
来源:AcWing

class Solution {
public:
    bool isMatch(string s, string p) {
        int n = s.size(), m = p.size();
        vector<vector<bool>> f(n + 1, vector<bool>(m + 1, false));
        s = ' ' + s, p = ' ' + p;
        f[0][0] = true;
        for(int i = 0; i <= n; i ++ )
            for(int j = 1; j <= m; j ++ ) {
                if(i > 0 && (s[i] == p[j] || p[j] == '.'))
                    f[i][j] = f[i][j] | f[i - 1][j - 1];
                if(p[j] == '*') {
                    if(j >= 2) 
                        f[i][j] = f[i][j] | f[i][j - 2];
                    if(i > 0 && (s[i] == p[j - 1] || p[j - 1] == '.'))
                        f[i][j] = f[i][j] | f[i - 1][j];
                }
            }
        return f[n][m];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值