LeetCode(中等) 395. 至少有K个重复字符的最长子串 击败100%

395. 至少有K个重复字符的最长子串

题目描述

找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度。

示例 1:

输入:
s = “aaabb”, k = 3

输出:
3

最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。

示例 2:

输入:
s = “ababbc”, k = 2

输出:
5

最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。

第一种使用分治与递归击败100%的java

(代码与解释如下)

package com.ys;

import org.junit.Test;

/**
 *  找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度。

示例 1:

输入:
s = "aaabb", k = 3

输出:
3

最长子串为 "aaa" ,其中 'a' 重复了 3 次。

示例 2:

输入:
s = "ababbc", k = 2

输出:
5

最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。
执行用时 :1 ms, 在所有 Java 提交中击败了100.00% 的用户
内存消耗 :34.6 MB, 在所有 Java 提交中击败了83.69%的用户

思路:使用递归和分治法
 * @author 10249
 *
 */
public class Deal007 {
	@Test
	  public void longestSubstring() {
		  
		  	String s = "aaabcbcb";
			int k = 3;//测试用例
	        int len = s.length();
	        if (len == 0 || k > len){ System.out.println(0);}
	        if (k < 2)  System.out.println(len);

	        System.out.println(count(s.toCharArray(), k, 0, len - 1)); 
	    }
	
	  private static int count(char[] chars, int k, int p1, int p2) {
	        if (p2 - p1 + 1 < k) return 0;
	        int[] times = new int[26];  //  26个字母
	        //  统计每个字母的出现次数
	        for (int i = p1; i <= p2; ++i) {
	            ++times[chars[i] - 'a'];
	        }
	        //  如果该字符出现频次小于k,就不可能出现在结果子串中
	        //  分别排除,然后挪动两个指针
	        
	        while (p2 - p1 + 1 >= k && times[chars[p1] - 'a'] < k) {
	            ++p1;//p1向后
	        }
	        while (p2 - p1 + 1 >= k && times[chars[p2] - 'a'] < k) {
	            --p2;//p2向前
	        }

	        if (p2 - p1 + 1 < k) return 0;//如果最终的p1和p2比k还小就没有结果
	        //  得到临时子串,再递归处理
	        for (int i = p1; i <= p2; ++i) {
	            //  如果第i个不符合要求,分成左右两段分别继续递归
	            if (times[chars[i] - 'a'] < k) {
	                return Math.max(count(chars, k, p1, i - 1), count(chars, k, i + 1, p2));
	            }
	        }
	        return p2 - p1 + 1;//最终输出最长字串长度
	    }
}


第二种使用还是分治与递归

一开始的想法,有些不好

package com.ys;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
/**
 * 找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度。

示例 1:

输入:
s = "aaabb", k = 3

输出:
3

最长子串为 "aaa" ,其中 'a' 重复了 3 次。

示例 2:

输入:
s = "ababbc", k = 2

输出:
5

最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。

思路:使用递归和分治法
 * @author 10249
 *
 */
public class Deal006 {
	public int re = 0;//定义一个最大值,初始化为0
	@Test
	public void longestSubstring(){
		String s = "aaabcbcb";
		int k = 3;//测试用例
		getlongest(s, k);//调用递归函数
    	System.out.println(re);
		
    	
    	
	}
	
	 public void getlongest(String s, int k) {	// 分治
	    	int len = s.length();
	    	if(len == 0) return;

	    	int[] count = new int[26];
	    	for(char c : s.toCharArray()) {
	    		count[c-'a']++;//记录每个字母出现的次数
	    	}

	    	int l = 0;
	    	boolean greater = true;   // 记录是否所有字符个数都 > k
	    	// 进行分隔处理判断循环
	    	for(int i = 0; i < len; i++) {
	    		//如果所有的字母出现的次数都大于k则不执行下面的if语句
	    		if(count[s.charAt(i) - 'a'] != 0 && count[s.charAt(i) - 'a'] < k) {		
				if(i > l) {//判断要被分隔的字符串是否为一个,如果为一个就没有必要再递归
	                getlongest(s.substring(l, i), k);//因为有字母出现次数小于k,所以从那个小于k的字母的位置继续分隔,以此类推
	            }
				greater = false;//把记录是否所有字符个数都 > k设为false
	                        l = i + 1;//把分隔位置记录下来
	    		}
	    	}
	    	//判断是否被分割了,并且总体的长度大于分隔位置,因为上面的l+1了,所以如果被分割的右边为一个也没必要再递归
	    	//如果满足条件,就开始在对右边的字符串做同样的递归操作
	    	if(!greater && len > l) getlongest(s.substring(l, len), k);
	    	if(greater) {//知道最终不用分隔
	    		re = Math.max(re, len);//re为每次递归的最大长度,最终返回所有递归中的最大长度re
	    	}
	    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值