【DP,打表】最长不含重复字符的子字符串,丑数

版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/83180764

面试题48:最长不含重复字符的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含从’a’到’z’的字符。

用f(i)表示以i位置字符结尾的最长不含重复字符的子字符串的长度,则所求的就是i从0~n-1中最大的一个f(i)。

在遍历数组时,记录每个字符最后一次出现的位置

①当i号字符之前没有出现过时,f(i)=f(i-1)+1。
②当之前出现过,且不在f(i-1)指示的子串里出现时,即出现位置到i位置的距离 d>f(i-1),f(i)=f(i-1)+1。
③当之前出现过,且就在f(i-1)指示的子串中时,即d<=f(i-1),这时候f(i)=d。

#include<bits/stdc++.h>
using namespace std;

//输入数组的string常引用,输出满足条件的最大的f(i)的值 
int longestSubstringWithoutDuplication(const string& str) {
	int curLength = 0;//当前找到的长度,即当前的f(i) 
	int maxLength = 0;//到当前为止,最大的f(i) 

	int* position = new int[26];//存26个字母"上一次出现的位置下标"
	for(int i = 0; i < 26; ++i) 
		position[i] = -1;//初始化为-1,表示"之前没出现过" 

	for(int i = 0; i < str.length(); ++i) {//遍历字符串 
		int prevIndex = position[str[i] - 'a'];//该位置字符上一次出现的位置下标 
		if(prevIndex < 0 || i - prevIndex > curLength)//情况①或② 
			++curLength;//f(i)=f(i-1)+1
			//反复出现这种情况时,curLength是单调增加的
			//所以不需要担心漏记录了中间出现的某些比两边大的长度
			//不可能出现,因为是单调增加的(单调减少就不行)
			//这时不对maxLength做无用的更新,因为更新了也会被后面的更新覆盖掉 
		else {//情况③ 
			if(curLength > maxLength)//更新最大f(i) 
				maxLength = curLength;
			curLength = i - prevIndex;//f(i)=d
		}
		position[str[i] - 'a'] = i;
	}
	//最终更新一次最大f(i),因为可能以情况①或者②结束 
	if(curLength > maxLength)
		maxLength = curLength;

	delete[] position;
	return maxLength;
}

int main() {
	string ok="abcacfrar";
	printf("%d\n",longestSubstringWithoutDuplication(ok));//4
	return 0;
}

面试题49:丑数

我们把只包含因子2、3和5的数称作丑数(Ugly Number)。求按从小到大的顺序的第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做第一个丑数。

传统解法是把输入的数字不断除以2、3、5,最后得到1就是丑数。用空间可以换时间,将已经得到的丑数从小到大打表;如需计算,表中下一个丑数就是:
m i n ( 2 × T 2 , 3 × T 3 , 5 × T 5 ) min(2 \times T_2,3 \times T_3,5 \times T_5)
其中 T k T_k 表示当前丑数表中的某个数,这个数乘以k后大于丑数表中最大数,且是满足该条件的所有数中最小的一个。

#include<bits/stdc++.h>
using namespace std;

//三个数找最小 
int Min(int number1, int number2, int number3) {
	int min = (number1 < number2) ? number1 : number2;//min(n1,n2)
	min = (min < number3) ? min : number3;//min(min(n1,n2),n3)
	return min;
}

//输入要寻找的丑数在顺序丑数表中是第几个,计算并返回该丑数 
int GetUglyNumber_Solution(int index) {
	if(index <= 0)//输入合法性 
		return 0;

	int *pUglyNumbers = new int[index];//第index个丑数下标为index-1 
	pUglyNumbers[0] = 1;//1是最小的丑数 
	int nextUglyIndex = 1;//下一个要找的丑数在丑数表中下标 

	//初始化T2,T3,T5的地址,都是&pUglyNumbers[0]
	int *pMultiply2 = pUglyNumbers;
	int *pMultiply3 = pUglyNumbers;
	int *pMultiply5 = pUglyNumbers;

	//一直找,找完下标为index-1的,当nextUglyIndex=index时停止 
	while(nextUglyIndex < index) {
		//min(T2,T3,T5)
		int min = Min(*pMultiply2 * 2, *pMultiply3 * 3, *pMultiply5 * 5);
		pUglyNumbers[nextUglyIndex] = min;//就是下一个丑数 

		//更新下次T2(的地址):T2*2要刚好大过当前表中最大丑数 
		while(*pMultiply2 * 2 <= pUglyNumbers[nextUglyIndex])
			++pMultiply2;
		//更新下次T3(的地址):T3*3要刚好大过当前表中最大丑数 
		while(*pMultiply3 * 3 <= pUglyNumbers[nextUglyIndex])
			++pMultiply3;
		//更新下次T5(的地址):T5*5要刚好大过当前表中最大丑数 
		while(*pMultiply5 * 5 <= pUglyNumbers[nextUglyIndex])
			++pMultiply5;

		++nextUglyIndex;//下次循环要找的丑数下标+1 
	}

	//要找的丑数就是pUglyNumbers[index-1] 
	int ugly = pUglyNumbers[nextUglyIndex - 1];
	delete[] pUglyNumbers;
	return ugly;
}

int main() {
	cout<<GetUglyNumber_Solution(1500)<<endl;//859963392
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SHU15121856/article/details/83180764