* 面试题48:最长不含重复字符的子字符串+长度
* 题目:请从字符串中找出一个最长的不包含重复自负的子字符串,计算该子字符串的长度。
* 假设字符串中只包含'a'~'z'的字符。
* 例如,在字符串"arabcacfr"中,最长的不含重复字符的子字符串是"acfr",长度为4
*
* 思路:运用东岱规划的思想进行解题,设定f(i)表示以第i格字符串为结尾的不包含重复自负的子字符串的最长长度。
* 从左到右逐一扫描字符串中的每一个字符,其中
* 当第i个字符之前没有出现过,则f(i) = f(i-1)+1
* 当第i个字符之前出现过,首先计算第i个字符和它上次出现的字符串中的位置的距离,记为d,则分为两种情况:
* 若d小于等于f(i-1),此时重复的字符出现在f(i-1)对应的最长字符串中,因此f(i) = d
* 若d大于f(i-1),此时重复的字符出现在f(i-1)的前面,不在f(i-1)对应的字符串中,因此不必考虑对f(i)的影响,因此f(i) = f(i-1)+1
*
* https://www.cnblogs.com/yongh/p/9951159.html
package Test;
public class No48LongestSubStringWithoutDuplication {
/*
* 面试题48:最长不含重复字符的子字符串+长度
* 题目:请从字符串中找出一个最长的不包含重复自负的子字符串,计算该子字符串的长度。
* 假设字符串中只包含'a'~'z'的字符。
* 例如,在字符串"arabcacfr"中,最长的不含重复字符的子字符串是"acfr",长度为4
*
* 思路:运用东岱规划的思想进行解题,设定f(i)表示以第i格字符串为结尾的不包含重复自负的子字符串的最长长度。
* 从左到右逐一扫描字符串中的每一个字符,其中
* 当第i个字符之前没有出现过,则f(i) = f(i-1)+1
* 当第i个字符之前出现过,首先计算第i个字符和它上次出现的字符串中的位置的距离,记为d,则分为两种情况:
* 若d小于等于f(i-1),此时重复的字符出现在f(i-1)对应的最长字符串中,因此f(i) = d
* 若d大于f(i-1),此时重复的字符出现在f(i-1)的前面,不在f(i-1)对应的字符串中,因此不必考虑对f(i)的影响,因此f(i) = f(i-1)+1
*
* https://www.cnblogs.com/yongh/p/9951159.html
* */
static StringBuilder sb = new StringBuilder();//记录最长的无重复字符的子字符串
public static void main(String[] args) {
// TODO Auto-generated method stub
No48LongestSubStringWithoutDuplication l = new No48LongestSubStringWithoutDuplication();
String s = "arabcacfr";
System.out.println("字符串中最长的不含重复重复的子字符串长度是"+l.LongestSubStringWithoutDuplication(s));
System.out.println("其子字符串为"+sb.toString());
}
//计算出不含重复字符的子字符串长度
private int LongestSubStringWithoutDuplication(String s) {
// TODO Auto-generated method stub
if(s == null || s.length() == 0)
return -1;
int preLength = 0;//f(i-1)
int curLength = 0;//f(i)
int maxLength = 0;
int[] position = new int[26];//记录a~z最新重复的位置
for(int i = 0; i < 26;i++)
position[i] = -1;
int startPos = 0;
for(int i = 0;i < s.length();i++) {
int preIndex = position[s.charAt(i)-'a'];
if(preIndex < 0 || i - preIndex > curLength) {
//preIndex < 0 表示该字符从未出现过 则f(i)=f(i-1)+1
//i 该字符的当前索引 preIndex 该字符的重复索引
//i - preIndex 表示d 第i个字符和它上一次出现在字符串中的位置的距离
//i - preIndex > curLength 表示重复字符出现在f(i-1)的前面 则f(i)=f(i-1)+1
curLength++;
if(curLength > maxLength)
maxLength = curLength;
}
else {
startPos = preIndex + 1;
if(curLength > maxLength)
maxLength = curLength;
// else表示 i - preIndex <= curLength 表示 重复字符在f(i-1)对应的字符串中 则f(i)=d=i-preIndex
curLength = i - preIndex;
}
position[s.charAt(i)-'a'] = i;//记录a~z当前位置字符的索引 记录最新的 旧的会被覆盖
}
if(curLength > maxLength)
maxLength = curLength;
for(int i = startPos,j = 0;j < maxLength;j++)
sb.append(s.charAt(i+j));
return maxLength;
}
}
* 面试49:丑数 逐个判断每个整数是不是丑数
* 题目:把只包含因子2,3,4的数称作丑数(Ugly Number).
* 求按从小到大的排序的第1500个丑数.
* 例如,6,8都是丑数,但14不是,因为它包含银子7.
* 习惯上把1当作第一个丑数
*
* 思路:构造一个判断该数字是否为丑数的函数
* 从小到大判断是否为丑数,直到找到要找的第N个丑数为止
*
* 优点:算法直观,代码简洁.
* 缺点是:每个数字都需要计算,即使该数字不是丑数,仍需要对其进行取余\取整操作.
* 算法的时间效率低,需要较高效的算法.
package Test;
public class No49GetUglyNumber_Simple {
/*
* 面试49:丑数 逐个判断每个整数是不是丑数
* 题目:把只包含因子2,3,4的数称作丑数(Ugly Number).
* 求按从小到大的排序的第1500个丑数.
* 例如,6,8都是丑数,但14不是,因为它包含银子7.
* 习惯上把1当作第一个丑数
*
* 思路:构造一个判断该数字是否为丑数的函数
* 从小到大判断是否为丑数,直到找到要找的第N个丑数为止
*
* 优点:算法直观,代码简洁.
* 缺点是:每个数字都需要计算,即使该数字不是丑数,仍需要对其进行取余\取整操作.
* 算法的时间效率低,需要较高效的算法.
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
No49GetUglyNumber_Simple g = new No49GetUglyNumber_Simple();
System.out.println("从小到大的顺序排列的第1500个丑数是:"+g.GetUglyNumber(1500));
}
//判断该数字number是否为丑数
private int GetUglyNumber(int index) {
// TODO Auto-generated method stub
if(index <= 0 )
return -1;
int number = 0;
int uglyFound = 0;
while(uglyFound < index) {
number++;
if(IsUgly(number)){
uglyFound++;
}
}
return number;
}
private boolean IsUgly(int number) {
// TODO Auto-generated method stub
while(number%2 == 0)
number /= 2;
while(number%3 == 0)
number /= 3;
while(number%5 == 0)
number /= 5;
if(number == 1)
return true;
else return false;
}
}
* 面试49:丑数 计算每一个丑数的值存入数组,求得第N个丑数
* 思路:使用空间换时间的概念
* 构造一个数组 存储丑数 计算从小到大的丑数
* 因为丑数的定义是2,3,5因子,所以 是由2,3,5相乘得到的
* 需要记录2,3,5都已经乘到哪一索引处,indexOf2,indexOf3,indexOf5然后每次乘玩的结果进行比较
* uglyArray[indexOf]*2 ,uglyArray[indexOf3]*3,uglyArray[indexOf5]*5去最小的存入丑数数组中
* 然后判断是哪一个完成了相乘,将其index位置,向后移动一个
* 然后接着找下一个丑数,直到找到第N个丑数为止,返回即可
*
* 优点:时间效率高,很快就能出来结果
* 缺点:空间换时间,利用了辅助空间
package Test;
public class No49GetUglyNumber_UseSpace {
/*
* 面试49:丑数 计算每一个丑数的值存入数组,求得第N个丑数
* 题目:把只包含因子2,3,4的数称作丑数(Ugly Number).
* 求按从小到大的排序的第1500个丑数.
* 例如,6,8都是丑数,但14不是,因为它包含银子7.
* 习惯上把1当作第一个丑数
*
* 思路:使用空间换时间的概念
* 构造一个数组 存储丑数 计算从小到大的丑数
* 因为丑数的定义是2,3,5因子,所以 是由2,3,5相乘得到的
* 需要记录2,3,5都已经乘到哪一索引处,indexOf2,indexOf3,indexOf5然后每次乘玩的结果进行比较
* uglyArray[indexOf]*2 ,uglyArray[indexOf3]*3,uglyArray[indexOf5]*5去最小的存入丑数数组中
* 然后判断是哪一个完成了相乘,将其index位置,向后移动一个
* 然后接着找下一个丑数,直到找到第N个丑数为止,返回即可
*
* 优点:时间效率高,很快就能出来结果
* 缺点:空间换时间,利用了辅助空间
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
No49GetUglyNumber_UseSpace g = new No49GetUglyNumber_UseSpace();
System.out.println("从小到大的顺序排列的第1500个丑数是:"+g.GetUglyNumber(1500));
}
public int GetUglyNumber(int index) {
// TODO Auto-generated method stub
if(index <= 0)
return -1;
int count = 1;
int[] uglyArray =new int[index];
uglyArray[0] = 1;
int indexOf2 = 0;
int indexOf3 = 0;
int indexOf5 = 0;
int numberOf2,numberOf3,numberOf5;
while(count < index) {
numberOf2 = uglyArray[indexOf2]*2;
numberOf3 = uglyArray[indexOf3]*3;
numberOf5 = uglyArray[indexOf5]*5;
int min = GetMin(numberOf2,numberOf3,numberOf5);
if(min == numberOf2)
indexOf2++;
if(min == numberOf3)
indexOf3++;
if(min == numberOf5)
indexOf5++;
uglyArray[count++] = min;
}
return uglyArray[index-1];
}
//三个数进行比较,返回最小的
public int GetMin(int number1,int number2,int number3) {
int min = (number1 < number2)?number1:number2;
min = (min < number3)?min:number3;
return min;
}
}