Leetcode刷题七

哈希表与字符串

哈希表是根据关键字值(key)直接进行访问的数据结构,它通过把关键字值映射到表中一个位置(数组下标)来直接访问,以加快查找关键字值的速度。这个映射函数叫做哈希函数,存放记录的数组叫做哈希表。
在这里插入图片描述
最简单的哈希:字符哈希

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int char_map[128]={0};
    string str = "abddhsjdsjbqndbnds";
    for(int i=0;i<str.length();i++)
        char_map[str[i]]++;
    for(int i=0;i<128;i++){
        if(char_map[i]>0)
            printf("[%c][%d]:%d\n",i,i,char_map[i]);
    }
    return 0;
}

哈希表排序整数:

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int random[10]={999,1,444,7,20,9,1,3,7,7};
    int char_map[1000]={0};
    //string str = "abddhsjdsjbqndbnds";
    for(int i=0;i<10;i++)
        char_map[random[i]]++;
    for(int i=0;i<1000;i++){
      for(int j=0;j<char_map[i];j++)
        printf("%d\n",i);
    }
    return 0;
}

时间复杂度是O(表长+n)n为元素个数

以拉链法构造哈希表:

将所有的哈希函数结果相同的结点连接在同一个单链表中。
若选定的哈希表长度为m,则可将哈希表定义为一个长度为m的指针数组t[0…m-1],指针数组中的每个指针指向哈希函数结果相同的单链表。

插入value:
将元素value插入哈希表,若元素value的哈希函数值为hash_key,将value对应的节点以头插法的方式插入到以t[hash_key]为头指针的单链表中。

查找value:
若元素value的哈希函数值为hash_key,遍历以t[hash_key]为头指针的单链表,查找链表各个节点的值域是否为value。

struct	ListNode{
		int val;
		ListNode* next;
		ListNode(int x):val(x),next(NULL){}
	};
	int hash_func(int key,int table_len){
		return key%table_len;
	}
	void insert(ListNode* hash_table[], ListNode* node, int table_len){
		int hash_key =  hash_func(node->val,table_len);
		node->next = hash_table[hash_key];
		hash_table[hash_key] = node;
	}
	bool search(ListNode* hash_table[],int value,int table_len){
		int hash_key =  hash_func(val,table_len);
		ListNode* head = hash_table[hash_key];
		while(head){
			if(head->val==val)
			  return true;
		   head=head->next;
		}
		return false;
	}
	
int main()
{
    const int TABLE_LEN=11;
    ListNode *hash_table[] = {0};
    vector<ListNode*> hash_node;
    int test[8] = {1,1,4,9,20,30,150,500};
    for(int i=0;i<8;i++)
        hash_node.push_back(new ListNode(test[i]));
    for(int i=0;i<hash_node.size();i++)
        Insert(hash_table,hash_node[i],TABLE_LEN);
    printf("Hash Table:\n");

    for(int i=0;i<TABLE_LEN;i++){
        printf("[%d]:",i);
        ListNode *head = hash_table[i];
        while(head){
            printf("->%d",head->val);
            head = head->next;
        }
        printf("\n");
    }
    printf("\n");
    for(int i=0;i<10;i++){
        if(Search(hash_table,i,TABLE_LEN))
            printf("%d is in the hash table.\n",i);
        else
            printf("%d is not in the hash table.\n",i);
    }
    //cout << "Hello world!" << endl;
    return 0;
}

第一题:最长回文串:leetcode 409
已知一只包括大小写字符的字符串,求用该字符串中的字符可以生成的最长回文字符串长度。
例如 s=“abccccddaa”,可生成的最长回文串字符串长度为9,如dccaaaccd、abccbccda等都对的。

int longestPalindrome(string s){
	int char_map[128]={0};
	int flag=0;
	int sum=0;
	for(int i=0;i<s.length();i++){
		char_map[s[i]]++;
	}
	for(int i=0;i<128;i++){
		if(char_map[i]%2==0)
			sum+=char_map[i];
		else {
			sum+=char_map[i]-1;
			flag=1;
		}
	}
	return sum+flag;
}

第二题:词语模式
已知字符串pattern与字符串str,确认str是否与pattern匹配。str与pattern匹配代表字符串str中的单词与pattern中的字符一一对应。
例如:
pattern=“abba” , str = “dog cat cat dog” 匹配
pattern = “abba”, str = “dog cat cat fish” 不匹配

思路:
1.设置单词(字符串)到pattern字符的映射(哈希);使用数组used[128]记录pattern字符是否使用。
2.遍历str , 按照空格拆分单词,同时对应的向前移动指向pattern字符的指针,每拆分出一个单词,判断:
如果该单词从未出现在哈希表中:
如果当前的pattern字符已被使用,则返回false;
将单词与当前指向的pattern字符做映射;
标记当前指向的pattern字符已使用
否则:
如果当前单词在哈希表中的映射字符不是当前指向的pattern字符,则返回false
3.若单词个数与pattern字符个数不匹配,返回false.

bool wordPattern(string pattern, string str){
		map<string,char> word_map;
		char used[128]={0};
		int pos=0;
		string word;
		for(int i=0;i<str.length();i++){
				if(str==' '){
					if(pos==pattern.length())  return false;
					if(word_map.find(word)==word_map.end()){
								if(used[pattern[pos]]) return false;
								word_map[word]=pattern[pos];
								used[pattern[pos]]=1;   //标记已使用
						}
					else {
								if(word_map[word]!=pattern[pos])  return false;
						}
						word="";
						pos++;
				}
				else 
				  word+=str[i];
		}
		if(pos!=pattern.length()) return false;
		return true;
}

第三题:通字符词语分组:
已知一组字符串,将所有的anagram(由颠倒字母顺序而构成的字)放到一起输出。leetcode 49

例如:[“eat”,“tea”,“tan”,“ate”,“nat”,“bat”]
返回:[[“ate”,“eat”,“tea”],[“nat”,“tan”],[“bat”]]

思路:
方法一:哈希表以内部进行排序的各个单词为key,以字符串向量<vector>为value,存储各个字符数量相同的字符串(anagram)
在这里插入图片描述
设置字符串到字符串向量的哈希表anagram,遍历字符串向量strs中的单词strs[i]:
1.设置临时变量str = strs[i],对str进行排序
2.若str未出现在anagram中,设置str到一个空字符串向量的映射。
3.将strs[i]添加到字符串向量anagram[str]中。
遍历哈希表anagram,将全部key对应的value push至最终结果中。
在这里插入图片描述

	vector<vector<string>> groupAnagrams(vector<string> & strs){
			map<string,vector<string>> Q;
			vector<vector<string>> result;
			for(int i=0;i<strs.size();i++){
				string str=strs[i];
				sort(str.begin(),str.end());
				if(Q.find(str)==Q.end()){
					vector<string> item;
					Q[str] = item;	
				}
				Q[str].push_back(str[i]);
		}
			map<string,vector<string>>::iterator it;
			for(it=Q.begin();it!=Q.end();it++){
				result.push_back((*it).second);
			}
			return result;
	}

方法二:哈希表以26个字母的字符数量(一个长度为26的vector,统计单词中各个字符的数量)为key,以字符串数量(vector)为value,存储各个字符数量相同的字符串(anagram)
在这里插入图片描述
思路:设置vector到字符串向量的哈希表anagram,遍历字符串向量strs中的单词strs[i]:
1.统计strs[i]中各个字符数量,存储至vec。
2.若vec未出现在anagram中,设置vec到一个空字符串向量的映射。
3.将strs[i]添加至字符串向量anagarm中。遍历哈希表anagarm,将全部的key对应的value push至最终结果中。

    void change_to_vector(string &str,vector<int>&vec){
		for(int i=0;i<26;i++)
		   vec.push_back(0);
		for(int i=0;i<str.length();i++){
		   vec[str[i]-'a']++;
		}
	}
	vector<vector<string>> groupAnagrams(vector<string> & strs){
			map<vector<int>,vector<string>> Q;
			vector<vector<string>> result;
			for(int i=0;i<strs.size();i++){
				vector<int > vec;
				change_to_vector(str,vec);
				if(Q.find(vec)==Q.end()){
					vector<string> item;
					Q[vec] = item;	
				}
				Q[vec].push_back(str[i]);
		}
			map<vector<int>,vector<string>>::iterator it;
			for(it=Q.begin();it!=Q.end();it++){
				result.push_back((*it).second);
			}
			return result;
	}

第四题:无重复字符的最长子串 leetcode 3
已知一个字符串,求用该字符串的无重复字符的最长子串的长度。
例如:
s = “abcabcbb” ->“abc” 3
s= “bbbb” “b” 1

思路:
1.设置一个记录字符数量的字符哈希,char_map;
2.设置一个记录当前满足条件的最长子串变量word;
3. 设置两个指针(指针i和begin)指向字符串的第一个字符;
4. 设置最长满足条件的子串的长度result;
5. i指针向后逐个扫描字符串中的字符,在这个过程中,使用char_map记录字符数量
如果word中没有出现该字符;对word尾部添加字符并检查result是否需要更新;
否则;bgein指针向前移动,更新char_map中的字符数量,直到字符s[i]的数量为1;更新word,
将word赋值为bgein与i之间的子串。
在整个过程中,使用bgein与i维护一个窗口,该窗口中的子串满足题目条件(无重复的字符),窗口线性向前滑动,整体的时间复杂度为o(n)。
在这里插入图片描述
在这里插入图片描述

int lengofLongestSubstring(string s){
  int result =0 ;
  int begin =0;
  int char_map[128]={0};
  string word;
  for(int i=0;i<s.length();i++){
			char_map[s[i]]++;
			if(char_map[s[i]]==1){
				word+=s[i];
				if(result<word.length())
				result=word.length();
			}
		else {
				 if(begin<i && char_map[s[i]]>1){
				 		char_map[begin]--;
				 		begin++;
				 }
  		 word="";
  		 for(int j=begin;j<=i;j++)
  		    word+=s[j];
		}
	}
  return result;
}

第五题:重复的DNA序列
将DNA序列看做是只包含[‘A’,‘C’,‘G’,‘T’]4个字符二代字符串,给一个DNA字符串,找到所有长度为10的且出现超过一次的子串。
Leetcode 187

s=“AAAAACCCCCQAAAACCCCCAAAAAGGGTTT”
Return:[“AAAAACCCCC”,“CCCCCAAAAA”]

思路:
枚举DNA字符串的中所有长度为10的子串,将其插入到哈希Map中,并记录子串数量;遍历哈希map,将所有出现超过一次的子串存储到结果中。算法复杂度O(n)

	vector<string> findRepeatDnaSequences(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]+=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;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值