Leetcode学习之哈希表与字符串 (3)

开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!


Leetcode学习之哈希表与字符串 (3)



1、重复的DNA序列 LeetCode187.

题目来源 L e e t C o d e   187.   R e p e a t e d   D N A   S e q u e n c e s LeetCode \ 187. \ Repeated \ DNA \ Sequences LeetCode 187. Repeated DNA Sequences
描述将DNA序列看作是只包含[‘A’,‘C’,‘G’,‘T’]4个字符的字符串,给一个DNA字符串,找到所有长度为10的且出现超过1次的子串

在这里插入图片描述

1.1 方法一:枚举+Map映射

分析
在这里插入图片描述

测试代码:

#include <stdio.h>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
	vector<string> findRepeatedDnaSequences(string s) {
		map<string, int> word_map;	//<单词,单词数量>的映射
		vector<string>	result;

		for (int i = 0; i < s.length(); i++) {

			string word = s.substr(i, 10);  //复制子字符串,要求从指定位置开始,并具有指定的长度。这是子串,子串是连续的。巧妙!

			if (word_map.find(word) != word_map.end()) {
				word_map[word] = word_map[word] + 1;
			}
			else{
				word_map[word] = 1;
			}
		}
		map<string, int> ::iterator it;
		for (it = word_map.begin(); it != word_map.end(); it++) {
			if (it->second > 1) { 
				result.push_back(it->first);
			}
		}
		return result;
	}
};

int main() {
	string s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT";
	Solution solve;
	vector<string> result = solve.findRepeatedDnaSequences(s);
	for (int i = 0; i < result.size(); i++) {
		printf("%s\n", result[i].c_str());
	}
	system("pause");
	return 0;
}

效果图
在这里插入图片描述

1.2 方法二:编码

分析
在这里插入图片描述

测试代码:

#include <stdio.h>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int g_hash_map[1048576] = { 0 };	//哈希太大了,需要全局数组

string change_int_to_DNA(int DNA){
	static const char DNA_CHAR[] = { 'A','C','G','T' };
	string str;
	for (int i = 0; i < 10; i++) {	//将一个长度为10的片段,从整数转为字符串
		str = str + DNA_CHAR[DNA & 3];
		DNA = DNA >> 2;
	}
	return str;
}

class Solution {
public:
	vector<string> findRepeatedDnaSequences(string s) {   //s.size() = 32
		vector<string> result;\

		if (s.length() < 10) {
			return result;
		}
		for (int i = 0; i < 1048576; i++) {	//每次调用时需要更新全局数组
			g_hash_map[i] = 0;
		}
		int char_map[128] = { 0 };
		char_map['A'] = 0;
		char_map['C'] = 1;	//设置字符到整数的转换数组
		char_map['G'] = 2;
		char_map['T'] = 3;
		int key = 0;		//将DNA字符串的前10个字符

		for (int i = 9; i >= 0; i--) {
			key = (key << 2) + char_map[s[i]];
		}
		g_hash_map[key] = 1;
		for (int i = 10; i < s.length(); i++) {
			key = key >> 2;
			key = key | (char_map[s[i]] << 18);
			g_hash_map[key]++;
		}
		for (int i = 0; i < 1048576; i++) {
			if (g_hash_map[i] > 1) {
				result.push_back(change_int_to_DNA(i));
			}
		}	//将出现次数大于2的片段push进入结果
		return result;
	}
};

int main() {
	string s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT";
	Solution solve;
	vector<string> result = solve.findRepeatedDnaSequences(s);
	for (int i = 0; i < result.size(); i++) {
		printf("%s\n", result[i].c_str());
	}
	system("pause");
	return 0;
}

效果图
在这里插入图片描述


2、最小窗口子串 LeetCode 76.

题目来源 M i n i m u m   W i n d o w   S u b s t r i n g Minimum \ Window \ Substring Minimum Window Substring
描述已知字符串S与字符串T,求在S中的最小窗口(区间),使得这个区间中包含了字符串T中的所有字符
在这里插入图片描述
分析
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试代码:

#include <stdio.h>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
private:
	//map_s[],map_t[]记录字符串里面各字符的个数,vector<int> 记录字符串中有哪些字符
	//这两个数组是字符哈希数组 map_s代表当前处理的窗口区间的字符数量;map_t代表子串T的字符数量
	bool is_window_ok(int map_s[], int map_t[], vector<int> &vec_t) {
		for (int i = 0; i < vec_t.size(); i++) {	//利用vec_t遍历t中出现的字符
			if (map_s[vec_t[i]] < map_t[vec_t[i]]) {
				return false;	//如果s出现该字符的数量小于t中出现该字符的数量
			}
		}
		return true;
	}
public:
	//i窗口尾指针
	//begin窗口头指针

	string minWindow(string s, string t) {
		const int MAX_ARRAY_LEN = 128;	//char 0-127.利用数组下标记录字符个数

		int map_t[MAX_ARRAY_LEN] = { 0 };	//记录t字符串的各字符个数
		int map_s[MAX_ARRAY_LEN] = { 0 };	//记录s字符串的各字符个数
		vector<int>	vec_t;		//记录t字符串中有哪些字符、

		for (int i = 0; i < t.length(); i++) {
			map_t[t[i]]++;		//遍历t,记录t字符串字符个数
		}

		for (int i = 0; i < MAX_ARRAY_LEN; i++) {
			if (map_t[i] > 0) {
				vec_t.push_back(i);
			}	//	遍历,将字符串t中出现的字符存储到vec_t中
		}
		int window_begin = 0;	//最小窗口起始指针
		string result;	//最小窗口对应的字符串

		for (int i = 0; i < s.length(); i++) {	//i代表了窗口的尾指针
			map_s[s[i]]++;	//将尾指针指向的字符添加搭配表示窗口的map中
			while (window_begin < i){	//窗口的头指针不能超过尾指针
				char begin_ch = s[window_begin];

				if (map_t[begin_ch] == 0) { //如果当前头指针指向的字符没有在字符串t中出现
					window_begin++;  //窗口头指针前移
				}	//头指针指向的字符出现在T中,窗口内有超过该字符个数的字符
				else if (map_s[begin_ch] > map_t[begin_ch]) {
					map_s[begin_ch]--;  //头指针前移,它指向的字符减少1
					window_begin++;		//窗口头指针前移
				}
				else{
					break;	//除了1,2两个条件,其他情况都跳出循环
				}
			}	//检查此时的窗口是否包含字符串t

			if (is_window_ok(map_s, map_t, vec_t)) {
				int new_window_len = i - window_begin + 1;	//计算新字符串长度
				if (result == "" || result.length() > new_window_len) {
					result = s.substr(window_begin, new_window_len);
				}	//替换窗口所对应的字符串  结果字符串为空或者当前窗口字符串更小的时候更新结果
			}
		}
		return result;
	}
};

int main() {
	Solution solve;
	string result = solve.minWindow("ADOBECODEBANC", "ABC");
	printf("%s\n", result.c_str());
	result = solve.minWindow("MADOBCCABEC", "ABCC");
	printf("%s\n", result.c_str());
	result = solve.minWindow("aa", "aa");
	printf("%s\n", result.c_str());
	system("pause");
	return 0;
}

效果图
在这里插入图片描述


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值