剑指Offer面试题(第二十九天)面试题48、49(无辅助空间)、49(有辅助空间)

 * 面试题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;
	}

}

猜你喜欢

转载自blog.csdn.net/weixin_43137176/article/details/89513436