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; } };
本文作者:Lxx-123
本文链接:https://www.cnblogs.com/l-xx123/p/18713151
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步