Leecode - week1(1-10)

1. Two Sum - leecode题库

思路

使用哈希表(哈希表可以在O(1)的时间内找到是否存在一个数),我们遍历当前下标元素x的时候,只需要判断这个元素之前是否存在等于target - x
从前向后扫描,每扫描一个数就将他放到哈希表里面,当扫描到s[i]的时候,就看前面是否存在一个数字等于target - s[i],每个数字进行插入和查询哈希表一次,时间复杂度为O(n)

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)){ // count方法返回r出现的次数,已经找到两个数的和是target
                return {heap[r], i};
            }else{ // 将当前数字插入到哈希表中
                heap[nums[i]] = i;
            }
        }
        return {}; // 避免警告,最好加上,虽然不会执行
    }
};

2.两数相加

思路

在这里插入图片描述
从个位开始计算,就是从链表的第一个数(最右边),计算第一个链表的数值+第二位连表内的数值+进位,三个数字的和%10 得到当前位置的和,用一个变量记录进位

虚拟头结点的使用:

虚拟头结点(dummy node)在链表操作中常用于简化边界条件的处理。以下是它的主要作用和好处:
简化逻辑:在处理链表时,尤其是在插入或删除节点时,常常需要处理头节点的特殊情况。使用虚拟头结点,可以避免这些特殊情况,因为你总是可以在虚拟头结点之后插入新节点。
避免空指针异常:当你开始构建结果链表时,虚拟头结点的存在可以让你在未创建第一个有效节点之前就能安全地进行指针操作,避免空指针的错误。
易于返回结果:因为虚拟头结点的下一个节点就是结果链表的头节点,所以在函数返回时,只需返回 dummy->next,而无需再检查链表是否为空或处理头节点的特殊情况。
简单来说,虚拟头结点的使用使得链表操作更加简洁和安全。你觉得这样解释清楚了吗?

/**
 * 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);
        auto 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 -> next = new ListNode(t % 10);
            cur = cur->next;
            t /= 10;
            }
            return dummy->next;// 返回实际的链表
        }
      
};

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

思路

对于从第一个数字开始,总共又n-1个字串,对于从第二个数开始,总共又n-2个字串…依此类推,所以总共的情况大约为 ( n 2 ) / 2 (n^2)/2 (n2)/2种,那么需要从这总共的情况中,找到最大的那个。思路就转换成:如何枚举所有情况,并取最大值。
在这里插入图片描述
这里采用双指针算法,i,j两个指针,每当i向后移动一格子i',j必然要么为当前位置,要么向后移动成为j'(可以用反证法证明),这样就只需要从左往右走一遍。使用Hash表维护当前序列元素出现的次数,当i向后移动一格,如果不满足元素不重复,那必然是s[i + 1]大于1,此时让j向后移动,直到s[i + 1] = 1
在这里插入图片描述

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> heap;
        int res = 0;// 记录最大值
        for(int i = 0, j = 0; i < s.size(); i ++){
            heap[s[i]] ++;
            while(heap[s[i]] > 1){
                heap[s[j ++]] --;//j向后移动,当前位置哈希表删除
            }
            res  = max(res, i - j + 1);
        }
        return res;
    }
};

补充C++知识点

unordered_map

在 C++ 中,unordered_map 是标准模板库(STL)中的一个关联容器,它基于哈希表实现。unordered_map 允许你存储键值对(key-value pairs),并且可以非常快速地进行查找、插入和删除操作。

以下是一些关于 unordered_map 的基本用法:

  1. 包含头文件
    要使用 unordered_map,你需要包含头文件 <unordered_map>

    #include <unordered_map>
    
  2. 声明
    声明一个 unordered_map 时,你需要指定键(key)和值(value)的类型。

    std::unordered_map<KeyType, ValueType> myMap;
    
  3. 插入元素
    使用 insert 方法或方括号 [] 操作符来插入元素。

    // 使用 insert 方法
    myMap.insert(std::make_pair("key1", "value1"));
    
    // 使用方括号操作符
    myMap["key2"] = "value2";
    
  4. 访问元素
    使用方括号 [] 操作符来访问元素。

    std::string value = myMap["key1"];
    
  5. 查找元素
    使用 find 方法来查找元素。

    auto it = myMap.find("key1");
    if (it != myMap.end()) {
        std::cout << "Found: " << it->second << std::endl;
    } else {
        std::cout << "Not found" << std::endl;
    }
    
  6. 删除元素
    使用 erase 方法来删除元素。

    // 删除键为 "key1" 的元素
    myMap.erase("key1");
    
    // 删除迭代器指向的元素
    myMap.erase(it);
    
  7. 遍历
    使用迭代器遍历 unordered_map

    for (auto it = myMap.begin(); it != myMap.end(); ++it) {
        std::cout << it->first << " : " << it->second << std::endl;
    }
    
  8. 大小
    使用 size 方法来获取 unordered_map 中元素的数量。

    std::size_t size = myMap.size();
    
  9. 清空
    使用 clear 方法来清空 unordered_map

    myMap.clear();
    

unordered_map 的性能通常比 map 更好,因为 unordered_map 使用哈希表,而 map 使用红黑树。但是,unordered_map 的元素顺序是不确定的,而 map 则按照键的顺序存储元素。

请注意,unordered_map 的键必须是可哈希的,并且必须能够与等号操作符一起使用以比较键值。

c++ auto介绍

auto 关键字在 C++ 中用于自动推断变量的类型。编译器根据初始化表达式的类型来确定变量的类型。使用 auto 的优点包括:

  1. 简化代码:减少类型声明的冗长性,特别是对于复杂类型(如迭代器、lambda 表达式等)。
  2. 类型安全:依然保持类型安全,编译器会检查推断的类型是否符合使用要求。
  3. 方便维护:如果类型发生变化,使用 auto 的地方不需要修改,减少了维护成本。
    举一个例子:
auto x = 5;          // x 的类型为 int
auto y = 3.14;       // y 的类型为 double
std::vector<int> vec = {1, 2, 3};
auto it = vec.begin(); // it 的类型为 std::vector<int>::iterator
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值