算法:字符串数组问题

本文探讨了如何利用哈希表解决字符串数组相关的算法问题,包括在长字符串中匹配子串、检查字符串中字符的独特性、验证两个字符串是否为彼此的置换、用报纸字母构造消息以及找到数组中最长连续元素序列的长度。还提到了避免暴力求解的Rabin-Karp算法,并强调在查找最长公共子串时要注意边界条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法:字符串数组问题

主要工具:hash table

在长度为n的母串中匹配长度为m的子串

Brute-force算法:(暴力求解)顺序遍历母串,将每个字符作为匹配字符,判断是否匹配子串。时间复杂度O(m*n)

char * Strstr(const char *str,  const char * target)
{
    if (! *target)
        return str;
    char *p1 = (char*)str;
    while(*p1)
    {
        char *p1Begin = p1;
        *p2 = (char*) target;
        while(*p1 && *p2 && *p1==*p2)
        {
            p1++;
            p2++;
        }
        if ( !*p2 )
            return p1Begin;
        p1 = p1Begin+1;
    }
    return NULL; 
}

Rabin-Karp算法:
在这里插入图片描述

确定字符串中的字符是否唯一

hashmap:

bool is unique(string input)
{
    bitset<256> hashMap;
    for(int i=0; i<input.length; i++)
    {
        if(hashmap[(int)input[i]])
        {
            return false;
        }
        hashMap[int)input[i]] = 1;
    }
    return true;
}
给定两个字符串确定它们是否是彼此的置换:
bool isPermutation(string stringA, string stringB)
{
    if (stringA.length() != stringB.length())
    {
        return false;
    }
    unordered_map<char, int> hashMapA;
    unordered_map<char,int> hashMapB;
    for(int  i = 0; i < stringA.length(); i++)
    {
        hashMapA[stringA[i]]++;
        hashMapB[stringB[i]]++;
    }
    if(hashMapA.size() != hashMapB.size())
    {
        return false;
    }
    unordered_map<char, int>::iterator it;
    for(it = hashMapA.begin(); it != hashMapA.end(); it++)
    {
        if(it->second != hashMapB[it->first])
        {
             return false;
        }
    }
    return ture;
}

将newspaper和message作为两个字符串,检查消息是否可以用报纸中的字母组成

message中任意字符出现次数要小于其在newspaper中出现的次数

bool isCompose(string newspaper, string message)
{
    unordered_map<chat, int> hashMap;
    int i;
    if(newspaper.length() < message.length())
    { 
        return false;
    }
    for(int i = 0; i < newspaper.length(); i++)
    {
        hashMap[newspaper[i]]++;
    }
    for (i = 0; i < message.length; i++)
    {
        if(hash.count(message[i]) == 0)
            return false;
        if(--hashMap[message[i]] < 0)
            return false;
    }
}
return true;

在一个数组中查找是否有其中两个数字相加的和为目标数

vector<int> addsToTarget(vector<int> &numbers, int target)
{
    unordered_map<int, int> numToindex;//哈希表
    vector<int> vi(2);//保存符合条件的两个数
    for( auto it = numbers.begin; it != numbers.end(); it++)
    {
        if(numToindex.count(target-*it))//当找到第二个数时便进入
        {
            vi[0] = numToindex[target - *it] + 1;
            vi[1] = (int)(it - numbers.begin()) + 1;
            return vi;//返回值为vector
        }
        numToindex[*it] = (int)(it - numbers.begin());//相当于保存第一个数的下标
    }
}
获取数组中最长连续元素序列的长度

用hash表存储元素的上一位和下一位,更新最小值和最大值就能唯一确定序列

struct bound
{
	int high;
	int low;
	bound(int h = 0, int l = 0)
	{
		high = h;
		low = l;
	}
};
int longestConsecutive(vector<int> &num)
{
	unordered_map<int, bound> table;
	int local;
	int maxLen = 0;

	for (int i = 0; i < num.size(); i++)
	{
		if (table.count(num[i]))//将每一个元素都放入hash表中,并跳过重复元素
			continue;
		local = num[i];
		int low = local;
		int high = local;
		
		if (table.count(local - 1))//查找当前元素-1是否在哈希表中
		{
			low = table[local - 1].low;更新最小值
		}
		if (table.count(local + 1))//查找当前元素+1是否在哈希表中
		{
			high = table[local + 1].high;//更新最大值
		}
        //对于没有连续序列的单个元素,low与high都等于自身
        //对于连续序列,low和high将更新为当前最小值和最大值
		table[low].high = table[local].high = high;
		table[high].low = table[local].low = low;

		if (high - low + 1 > maxLen)
		{
			maxLen = high - low + 1;
		}

	}
	return maxLen;
}

查找最长公共子串

注意防止访问越界

int LongestCommonSubstring(string &A, string &B)
{
	if (A.empty() || B.empty())
	{
		return 0;
	}
	int lcs = 0, lcs_temp = 0;
	for (int i = 0; i < A.size(); ++i)
	{
		for (int j = 0; j < B.size(); ++j)
			lcs_temp = 0;
		{
			while ((i + lcs_temp < A.size()) && (j + lcs_temp < B.size()) && (A[i + lcs_temp] == B[j + lcs_temp]))
			{
				++lcs_temp;
			}
			if (lcs_temp>lcs)
			{
				lcs = lcs_temp;
			}
		}	
	}
	return lcs;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值