在c++中很多种映射。
unordered_map 和 map 以及 multimap 、 hash_map。其中unordered_map 是用 hash 完成的,map和multimap 是用 红黑树完成的。
unorder_map 可以在O(1) 找到查找的值,map 需要O(log(n))。
可是map 是有序的,找最小值,最大值等等时间复杂度为O(log(n)) ,而unorder_map 需要O(n)。
mulitmap 的键可以重复,map 的键不能重复。
map的所有操作
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数
int main()
{
map<int, int> test;
test[1]++;
test[1]++;
test[2] += 10;
cout << test.count(10) << endl; //找map 中有没有键值为10的
auto result = test.find(10) != test.end() ? 1 : 0; //和用count() 效果一样
cout << result << endl;
auto r2 = test.lower_bound(1); //返回键值>=给定元素的第一个位置
cout << r2->first << " " << r2->second << endl;//1 2
r2 = test.upper_bound(1); //返回键值>给定元素的第一个位置
cout << r2->first << " " << r2->second << endl;//2 10
auto r3 = test.equal_range(1); //equal_range会返回一个pair,first是一个迭代器,指向匹配的第一个元素,second指向后一个。
cout << r3.first->first << " " << r3.first->second << endl; //1 2
cout << test.size() << endl;
return 0;
}
大楼轮廓 LintCode131
题目:
输入:
[
[1, 3, 3],
[2, 4, 4],
[5, 6, 1]
]
输出:
[
[1, 2, 3],
[2, 4, 4],
[5, 6, 1]
]
说明:
建筑物如下图所示,黄色部分表示建筑物
题解:
建两个map。curHeightMap和memoOutlineMap。
curHeightMap 记录当前位置上所有建筑的高度。
memoOutlineMap 记录每个“建筑边界”的最大高度。
class Solution {
public:
struct Node{
bool isUp;
int position;
int height;
Node(bool a = 0, int b = 0, int c = 0){
isUp = a;
position = b;
height = c;
}//Node
bool operator < (const Node& s2)const{
if (position != s2.position){
return position < s2.position;
}//if
else if(isUp != s2.isUp){
return isUp == false ? true : false;
}//else if
else if (isUp == s2.isUp){
return true;
}
}
};
vector<vector<int>> buildingOutline(vector<vector<int>> &buildings) {
static Node nodes[1000000];
int buildingsLen = buildings.size();
for (int i = 0; i < buildingsLen; i++){
nodes[i * 2] = Node(true, buildings[i][0], buildings[i][2]);
nodes[i * 2 + 1] = Node(false, buildings[i][1], buildings[i][2]); //building end position
}//for
sort(nodes, nodes + buildingsLen * 2);
map<int, int> curHeightMap, memoOutlineMap;
buildingsLen *= 2;
for (int i = 0; i < buildingsLen; i++){
if (nodes[i].isUp){
curHeightMap[nodes[i].height]++;
}//if (nodes[i].isUp)
else{ // nodes[i].isDown
if (curHeightMap[nodes[i].height] == 1){
curHeightMap.erase(nodes[i].height);
}//inner if
else{
curHeightMap[nodes[i].height]--;
}
}//extren else
if (curHeightMap.empty()){// 如果当前的htMap清空了,那么当前位置的最大高度置为0
memoOutlineMap[nodes[i].position] = 0;
}//if
else{
memoOutlineMap[nodes[i].position] = curHeightMap.rbegin()->first;
//cout << curHeightMap.rbegin()->first << endl;
}
}//for
vector<vector<int>> result;
int start = 0;
int height = 0;
int curMaxHeight;
vector<int> newRecord;
for (auto temp : memoOutlineMap){
curMaxHeight = temp.second;
if (height != curMaxHeight){ //在temp.second 这点高度发生变化
if (height != 0){ // 需要记录Outline
newRecord.clear();
newRecord.push_back(start);
newRecord.push_back(temp.first);
newRecord.push_back(height);
result.push_back(newRecord);
}//inner for
start = temp.first;
height = curMaxHeight;
}//if
}//for
return result;
}
};
int main()
{
vector<vector<int>> data,r;
data.push_back({ 1, 3, 3 });
data.push_back({ 2, 4, 4 });
data.push_back({ 5, 6, 1 });
Solution s;
r = s.buildingOutline(data);
return 0;
}
LongestSumSubArrayLength
题意:给你一个数字num , 和一个数组Array 。 要你找出一个子数组,它的和为 num , 同时长度要最大。
例子:
arr = {7,3,2,1,1,7,7,7} num = 7
其中有很多的子数组累加和等于7,但是最长的子数组是{3,2,1,1},所
以返回其长度4
题解:用前缀和 和 map 。map 的键为一个数t,值为前缀和t为最小下标。我们找当前的前缀和sum - map[k] == num 。 k 为 sum - num 的值。 而map 又是映射, 找到键为 sum - num 的 值,即为下标。
int maxLength(int arr[], int len,int k)
{
if (len == 0){
return 0;
}
map<int, int> HashMap;
HashMap[0] = -1;// 前缀和为0 时,下标为 -1
int maxL = 0, sum = 0;
for (int i = 0; i < len; i++){
sum += arr[i];
if (HashMap.count(sum - k) == 1){ //HashMap contain (sum - k) in key
maxL = max(maxL, i - HashMap[sum - k]);
}//if
if (HashMap.count(sum) == 0){ //HashMap not contain (sum) in key
HashMap[sum] = i;
}
}//for
return maxL;
}
void generateArray(int Arr[], int len)
{
srand(time(0));
for (int i = 0; i < len; i++){
Arr[i] = (int)rand() % 10 - (int)rand() % 10;
}
}
int main()
{
int arr[1000];
generateArray(arr,5);
for (int i = 0; i < 5; i++){
cout << arr[i] << " ";
}
cout << endl;
cout << maxLength(arr,5,5) << endl;
return 0;
}
找一个数组中 ,子数组中奇数和偶数 的数量相等,也是这题的一个变形。
Most_EOR
定义数组的异或和的概念:(相同为假,相异为真是异或)
数组中所有的数异或起来,得到的结果叫做数组的异或和,
比如数组{3,2,1}的异或和是,3^2^1 = 0
给定一个数组arr,你可以任意把arr分成很多不相容的子数组,你的目的是:
分出来的子数组中,异或和为0的子数组最多。
请返回:分出来的子数组中,异或和为0的子数组最多是多少?
题解:
异或有交换律和结合律。我们用任何数 ^ 0 等于 该数本身, 这个性质找异或和为 0 的划分。
用 map 加 dp ,map 记录了所有前缀异或和 对应的下标。dp 记录 下标为i 时,最多划分数。
如果当前i 的前缀异或和 等于 0 - i 中其中一个j前缀异或和 ,用 任何数 ^ 0 等于 该数本身 这个性质,可以得到,j + 1 到 i 的异或和一定为 0 , 可以得到 dp[i] = dp[j] + 1。
这里我们用了对拍。
对拍函数用的是dp 。如果:
if ((eors[i] ^ eors[j]) == 0)
也说明了 i 的 前缀异或和 等于 j 的异或和的 。因为两个相等的数异或等于 0 。
#pragma GCC optimize(3,"Ofast","inline")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
#include<cstdlib>
#include<bitset>
#include<climits>
#include<functional>
#include<unordered_set>
#include<unordered_map>
#include<time.h>
#define F(i,s,t) for(int i=(s);i<=(t);i++)
#define D(i,s,t) for(int i=(s);i>=(t);i--)
#define dBug(i) printf("Value=%d\n",i)
#define ddBug(i,j) printf("Value=%d %d\n",i,j)
#define ed putchar('\n')
#define FO freopen("D:\\in.txt","r",stdin)
#define IOS cin.tie(0) ,cout.tie(0), cout.sync_with_stdio(0)
typedef long long ll;
//const int INF = 1 << 30;
//const double EPS = 1e-6;
//#define MX 102
//#define Mod 10000
using namespace std;
int maxEOR(int arr[], int len)
{
int ans = 0, xor = 0, pre;
int dp[1000] = { 0 };
map<int, int> HashMap;
HashMap[0] = -1;
for (int i = 0; i < len; i++){
xor ^= arr[i];
if (HashMap.count(xor) == 1){
pre = HashMap[xor];
dp[i] = pre == -1 ? 1 : (dp[pre] + 1);
}//if
if (i > 0){
dp[i] = max(dp[i], dp[i - 1]);
}//if
HashMap[xor] = i;
ans = max(ans, dp[i]);
}//for
return ans;
}
int comparatot(int arr[], int len)
{
if (len == 0){
return 0;
}
int eors[1000]; // 表示第i位的异或和
int eor = 0;
for (int i = 0; i < len; i++){
eor ^= arr[i];
eors[i] = eor;
}//for
int dp[1000]; // dp[i] 表示 第i 位的答案
dp[0] = arr[0] == 0 ? 1 : 0;
for (int i = 1; i < len; i++){
dp[i] = eors[i] == 0 ? 1 : 0;
for (int j = 0; j < i; j++){
if ((eors[i] ^ eors[j]) == 0){ //note : 位运算的优先级
/*cout << eors[i] << endl;
cout << eors[j] << endl;
int temp = eors[i] ^ eors[j];
cout << temp << endl;*/
dp[i] = max(dp[i], dp[j] + 1);
}//if
}//for
dp[i] = max(dp[i], dp[i - 1]);
}//for
return dp[len - 1];
}
void generateArray(int Arr[], int len, int maxValue)
{
srand(time(0));
for (int i = 0; i < len; i++){
Arr[i] = (int)rand() % maxValue;
}
}
void printArray(int arr[], int len)
{
if (len == 0){
return;
}
for (int i = 0; i < len; i++){
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
int testTime = 5000;
int maxSize = 5;
int maxValue = 30;
int arr[1000];
bool succeed = true;
int res, comp;
for (int i = 0; i < testTime; i++){
generateArray(arr, maxSize, maxValue);
res = maxEOR(arr, maxSize);
comp = comparatot(arr, maxSize);
if (res != comp){
succeed = false;
printArray(arr, maxSize);
cout << res << endl;
cout << comp << endl;
break;
}//if
//cout << i << endl;
}//for
if (succeed){
cout << "Nice" << endl;
}
else{
cout << "Fucking" << endl;
}
return 0;
}
LeetCode187. 重复的DNA序列
所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。
编写一个函数来查找目标子串,目标子串的长度为 10,且在 DNA 字符串 s 中出现次数超过一次。
示例:
输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT"
输出:["AAAAACCCCC", "CCCCCAAAAA"]
题解:
双指针,和 map 。
遍历所有的长度为 10的子串,用 map 的 key 来存出现的字串,value 来存出现的次数。
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
string subDNA;
vector<string> sameDNACollect;
map<string, int> allSubDNA;
int time = s.length() - 10 + 1;
for (int i = 0; i < time; i++){
subDNA = s.substr(i,10);
if (allSubDNA.count(subDNA) == 0){
allSubDNA[subDNA] = 1;
}//if
else if(allSubDNA[subDNA] == 1){
sameDNACollect.push_back(subDNA);
allSubDNA[subDNA]++;
}
else{
allSubDNA[subDNA]++;
}
}//for
return sameDNACollect;
}
};
LeetCode219. 存在重复元素 II
给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
示例 1:
输入: nums = [1,2,3,1], k = 3
输出: true
题解:
用map,map的key 存 nums里面的数,map 的 value 存 最近一次出现在第几位。
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
map<int, int> numIndex;
int len = nums.size();
for (int i = 0; i < len; i++){
if (numIndex.count(nums[i]) == 1){
if (i - numIndex[nums[i]] <= k){
return true;
}
else{
numIndex[nums[i]] = i;
}//else
}//extren if
else{
numIndex[nums[i]] = i;
}
}//for
return false;
}
};
参考博客:https://blog.csdn.net/sevenjoin/article/details/81943864