LeetCode刷题总结(一)1-3

本文探讨了算法设计中的时间复杂度与空间复杂度权衡,以LeetCode经典问题为例,介绍了暴力求解、排序双指针和哈希表等方法。针对两数之和、两数相加及无重复字符的最长子串问题,展示了如何通过优化算法提升效率,如双指针技巧和哈希表的使用。

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

  算法中最主要的是要考虑时间复杂度,在时间低的情况下,再去考虑空间复杂度

(1)LeetCode1:两数之和

方法一:两层循环,依次遍历,暴力获取和为target的索引值,时间复杂度为o(n2)
方法二:先对整数数组进行排序,然后通过双指针的方式获取和为target的索引值,时间复杂度为o(logn),因为C++中排序函数的时间复杂度为o(logn)
方式三:通过哈希表这一数据结构(C++中为unordered_map),

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

(2)LeetCode2:两数相加

/**
 * 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;
        // 设置虚拟头节点dummy,这样就不用判断是否是第一位了;当然,虚拟头节点可以不加
        // 当要特判头节点的时候,我们才有可能用到虚拟头节点(即创建链表的时候我们要用if来判断一下是否为第一个节点)
        // cur是和节点的尾节点,每次链表更新插入都是从尾部插入更新的
        int t = 0; // 进位值
        while (l1 || l2 || t) { // 当l1/l2没有循环完,或者t进位值不等于0的话就继续循环
            // 若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;
    }
};

(3)LeetCode3:无重复字符的最长子串

如何考虑这类问题,首先题目会给我们一个序列,然后怎么把答案找出来呢?
注意一点:怎么把所有情况都枚举到 !
step1 : 一个n个字符的序列当中,共有多少个子串呢?
大约有(n^2/2)个子串
然后我们就要从这所有子串中把无重复的子串都拿出来,并挑选出长度最长的。为此,我们要做个分类,以子串结束(当然,找开始的也行)的节点来做分类,共有n种可能,从0开始,从1开始…一直到n-1(n-1就是自己一个构成的子串)开始;
现在我们假设确定了终点i,那我们就要找到一个最左的j与之匹配构成无重复的子串,最基本的解决方法就是通过遍历 i 左边所有的j字符一起的子串,这样遍历的时间复杂度是o(n),
做一个优化:(使用双指针算法)优化的前提理论是:
当我们当前的i字符遍历完后,向后推一步,i1,i1所对应的开始元素一定在i所对应的开始元素 j 后面,这样我们就不需要重复遍历了
j一定在j`的前面!若在后面,就不满足重复字符的定义了!
(双指针的主要优化就是避免吃回头草!)在这里插入图片描述
同时,为了验证重复性,我们可以利用哈希表来确定i,j之间每个字符出现的次数!每次i往后移一格,就把i + 1加到哈希表的集合当中去,并看下是否有重复元素,如果有重复,就让j往后移,直到没有重复元素为止。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> heap; //定义哈希表,统计每个元素出现的次数
        int res = 0; // res 是最大值
        for(int i = 0,j = 0; i < s.size(); i ++) { // i 为末尾指针,j为头指针, 循环是i一直往后移,当i已经移动完它这个位置的所有情况后,才会往后移动
            heap[s[i]] ++; // 将新的“i+1”插入到hash表中
            while(heap[s[i]] > 1) heap[s[j++]] --; //如果出现重复,j就要向后移动
            res = max(res, i - j +1); // 每移动一次,就要将其与之前的比较一次
        }
        return res;
    }
};
// unordered_map用于统计某个元素出现的次数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值