2月13日

前置知识

begin();end()正序迭代器
cbegin();cend() 返回 const 的begin();end()
rbegin();rend() 逆序迭代器
crbegin();crend() 返回 const 的 rbegin();rend()

begin();end()分别返回指向容器头的迭代器、指向容器尾的迭代器

示例代码:

int main ()
{
    std::vector<int> a{1,2,3,4,5};

    for (std::vector<int>::iterator iter=a.begin(); iter!=a.end(); ++iter){
        std::cout << "old element:" << *iter;// 打印元素

        (*iter) += 1;// 通过迭代器修改对应元素
        std::cout << ", new:" << *iter << std::endl;

    }
}

结果:
打印结果:
old element:1, new:2
old element:2, new:3
old element:3, new:4
old element:4, new:5
old element:5, new:6

rbegin(); rend() 返回逆序迭代器

例题:

1.假如一个数组里面,有一个数只出现一次,其余都出现两次,那么如何找出那个出现一次的数

1)异或法:

思路:
异或运算符(^):任何数和自己异或的结果是 0,任何数和 0 异或的结果是它本身。因此,可以通过异或运算将所有数字依次异或,最终剩下的就是只出现一次的数字。

#include <iostream>
using namespace std;
int main() {
	int z[7] = { 1,2,3,4,2,3,1 };
	int d=0;
	for (int nums : z) {
		d = d^nums;
	}
	cout << d;
}

2)使用哈希表

思路:
统计每个数字出现的次数,最后找到出现次数为 1 的数字。

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

int singleNumber(vector<int>& nums) {
    unordered_map<int, int> countMap;
    for (int num : nums) {
        countMap[num]++;
    }
    for (auto& pair : countMap) {
        if (pair.second == 1) {
            return pair.first;
        }
    }
    return -1; // 如果没有找到,返回一个默认值
}

int main() {
    vector<int> nums = {4, 1, 4, 6, 1};
    cout << "The single number is: " << singleNumber(nums) << endl;
    return 0;
}

2.给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

思路:

使用哈希表,读取数组时,检查哈希表中是否存在 target - current_element,若存在,则返回这两个元素的索引,没有就将当前元素及其索引存入哈希表。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> mp;
        for (int i = 0; i < nums.size(); i++) {
            int s = target - nums[i];
            if (mp.find(s) != mp.end()) {
                return {mp[s], i};
            }
            mp[nums[i]] = i;
        }
        return {};
    }
};

3.罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。

示例 1:

输入: s = "III"
输出: 3
示例 2:

输入: s = "IV"
输出: 4
示例 3:

输入: s = "IX"
输出: 9
示例 4:

输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:

输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.

提示:

1 <= s.length <= 15
s 仅含字符 ('I', 'V', 'X', 'L', 'C', 'D', 'M')
题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
关于罗马数字的详尽书写规则,可以参考 罗马数字 - 百度百科。

思路:

首先用哈希表,存储各个符号所对应的值
这一题是计算时,先对比该字符的值是否小于下一位的值,小于就取负数,反之正数

class Solution {
public:
        int romanToInt(string s) {
            unordered_map<char, int> symbol = {
            {'I', 1},
            {'V', 5},
            {'X', 10},
            {'L', 50},
            {'C', 100},
            {'D', 500},
            {'M', 1000},
        };
        int result=0;
        for(int i=0;i<s.size();++i){
            if(symbol[s[i]]<symbol[s[i+1]]){
                result-=symbol[s[i]];
            }else{
                result+=symbol[s[i]];
            }
        }
        return result;
    }
};

4.回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数
是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是。

示例 1:

输入:x = 121
输出:true
示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

提示:

-231 <= x <= 231 - 1

进阶:你能不将整数转为字符串来解决这个问题吗?

思路:反转字符串,对比两者是否相同;或者反转一半

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

5.两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

提示:

每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零

思路:
1.直接想法,转化成整数,这样无法实现,会溢出
2.直接在链表上相加,并用一个变量存储进位

/**
 * 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 = new ListNode(-1); // 哑节点
        ListNode* cur = head;
        int carry=0;
        while(l1||l2){
            int sum = carry;
            if (l1) {
                sum += l1->val;
                l1 = l1->next;
            }
            if (l2) {
                sum += l2->val;
                l2 = l2->next;
            }
            carry=sum/10;
            cur->next=new ListNode(sum % 10);
            cur = cur->next;
        }
        if(carry>0){
            cur->next = new ListNode(carry);
        }
        return head->next;
    }
};

3.递归法

/**
 * 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) {
        return add(l1, l2, 0);
    }
    ListNode* add(ListNode* l1, ListNode* l2, int carry) {
        if (!l1 && !l2 && carry == 0) {
            return nullptr;
        }
        int sum = carry;
        if (l1) sum += l1->val;
        if (l2) sum += l2->val;
        ListNode* node = new ListNode(sum % 10);
        carry = sum / 10;
        
        // 递归处理下一位
        node->next = add(
            l1 ? l1->next : nullptr,
            l2 ? l2->next : nullptr,
            carry
        );
        
        return node;
    }
};
posted @ 2025-02-14 11:20  Lxx-123  阅读(10)  评论(0)    收藏  举报