Java:找到没有任何数字和至少一个大写字符的最长子字符串

时间:2016-09-08 10:28:40

标签: java string algorithm data-structures

遇到编程练习并被卡住了。问题是:

  

您需要为电子邮件定义有效密码,但仅限于此   限制是:

     
      
  • 密码必须包含一个大写字符

  •   
  • 密码不应包含数字

         

    现在,给定一个String,找到最长子串的长度   是有效的密码。对于例如Input Str = "a0Ba",输出应该是   是2,因为“Ba”是有效的子串。

  •   

我使用了最长子字符串的概念而没有重复我之前已经做过的字符但是无法修改它以找到上述问题的解决方案。我没有重复字符的最长子字符串的代码是:

public int lengthOfLongestSubstring(String s) {
    int n = s.length();
    Set<Character> set = new HashSet<>();
    int ans = 0, i = 0, j = 0;
    while (i < n && j < n) {
        // try to extend the range [i, j]
        if (!set.contains(s.charAt(j))){
            set.add(s.charAt(j++));
            ans = Math.max(ans, j - i);
        }
        else {
            set.remove(s.charAt(i++));
        }
    }
    return ans;
}

17 个答案:

答案 0 :(得分:3)

怎么样

final String input = "a0Ba";

final int answer = Arrays.stream(input.split("[0-9]+"))
    .filter(s -> s.matches("(.+)?[A-Z](.+)?"))
    .sorted((s1, s2) -> s2.length() - s1.length())
    .findFirst()
    .orElse("")
    .length();

out.println(answer);

Arrays.stream(input.split("[0-9]+"))将原始字符串拆分为字符串数组。分隔符是任何数字序列(数字不允许,因此它们用作分隔符)。然后,创建一个流,以便我可以应用功能操作和转换。

.filter(s -> s.matches("(.+)?[A-Z](.+)?"))只保留流中至少包含一个大写字母的字符串。

.sorted((s1, s2) -> s2.length() - s1.length())按长度(desc)对流进行排序。

.findFirst()尝试获取流的第一个字符串。

如果没有找到字符串,

.orElse("")将返回一个空字符串。

.length();获取字符串的长度。

答案 1 :(得分:2)

我建议您将String拆分为一个没有数字的字符串数组:

yourString.split("[0-9]")

然后遍历此数组(表示数组a)以获取包含一个大写字符的最长字符串:

a[i].matches("[a-z]*[A-Z]{1}[a-z]*"); 

答案 2 :(得分:1)

您可以使用简单的数组。要使用的算法是动态滑动窗口。以下是静态滑动窗口的示例:What is a Sliding Window

算法应如下所示:

跟踪char数组的2个索引。这两个索引在这里将被称为frontback,表示数组的正面和背面。

拥有int(此处我将其命名为up)以跟踪大写char的数量。

将all设置为0。

使用while循环,如果front > N N是给定的char,则会终止该循环。

如果下一个字符不是数字,请向front添加1。然后检查char是否为大写。如果是,请将{1}添加到up

如果up至少为1,请在必要时更新最大长度。

如果下一个字符是数字,请继续检查以下char是否也是数字。将front设置为char不是数字且backfront-1的第一个索引。

输出最大长度。

答案 3 :(得分:1)

您可以使用我在O(n)时间内运行的解决方案,找到没有任何数字和大写字母的最长部分:

    String testString = "skjssldfkjsakdfjlskdssfkjslakdfiop7adfaijsldifjasdjfil8klsasdfŞdijpfjapodifjpoaidjfpoaidjpfi9a";

    int startIndex = 0;
    int longestStartIndex = 0;
    int endIndex = 0;
    int index = 0;
    int longestLength = Integer.MIN_VALUE;
    boolean foundUpperCase = false;

    while(index <= testString.length()) {
        if (index == testString.length() || Character.isDigit(testString.charAt(index))) {
            if (foundUpperCase && index > startIndex && index - startIndex > longestLength) {
                longestLength = index - startIndex;
                endIndex = index;
                longestStartIndex = startIndex;
            }
            startIndex = index + 1;
            foundUpperCase = false;
        } else if (Character.isUpperCase(testString.charAt(index))) {
            foundUpperCase = true;
        }
        index++;
    }

    System.out.println(testString.substring(longestStartIndex, endIndex));

答案 4 :(得分:0)

function ValidatePassword(password){
    var doesContainNumber = false;
    var hasUpperCase = false;

    for(var i=0;i<password.length;i++){
        if(!isNaN(password[i]))
            doesContainNumber = true;
        if(password[i] == password[i].toUpperCase())
            hasUpperCase = true;
    }

    if(!doesContainNumber && hasUpperCase)
        return true;
    else
        return false;
}

function GetLongestPassword(inputString){
    var longestPassword = "";
    for(var i=0;i<inputString.length-1;i++)
    {
        for (var j=i+1;j<inputString.length;j++)
        {
            var substring = inputString.substring(i,j+1);
            var isValid = ValidatePassword(substring);
            if(isValid){
                if(substring.length > longestPassword.length)
                {
                    longestPassword = substring;
                }
            }
        }
    }
    if(longestPassword == "")
    {
        return "No Valid Password found";
    }
    else
    {
        return longestPassword;
    }
}

答案 5 :(得分:0)

这是我使用c#的解决方案。我测试了一系列字符串,它给了我正确的值。使用拆分。没有正则表达式或子字符串。让我知道它是否有效;可以改进和更正。

public static int validPassword(string str)
    {
        List<int> strLength = new List<int>();
        if (!(str.All(Char.IsDigit)))
        {
            //string str = "a0Bb";
            string[] splitStrs = str.Split(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });


            //check if each string contains a upper case
            foreach (string s in splitStrs)
            {
                //Console.WriteLine(s);
                if (s.Any(char.IsUpper) && s.Any(char.IsLower) || s.Any(char.IsUpper))
                {
                    strLength.Add(s.Length);
                }
            }

            if (strLength.Count == 0)
            {
                return -1;
            }

            foreach (int i in strLength)
            {
                //Console.WriteLine(i);

            }
            return strLength.Max();
        }


        else
        {
            return -1;
        }

    }

答案 6 :(得分:0)

//最简单的方法:

String str = "a0Ba12hgKil8oPlk";
        String[] str1 = str.split("[0-9]+");
        List<Integer> in = new ArrayList<Integer>();
        for (int i = 0; i < str1.length; i++) {
            if (str1[i].matches("(.+)?[A-Z](.+)?")) {
                in.add(str1[i].length());
            } else {
                System.out.println(-1);
            }
        }
        Collections.sort(in);
        System.out.println("string : " + in.get(in.size() - 1));

答案 7 :(得分:0)

我认为这个解决方案可以处理所有可能的极端情况。它通过了在线评审中的所有测试用例。它是一个动态滑动窗口O(n)解决方案。

public class LongestString {

    public static void main(String[] args) {

        // String testString = "AabcdDefghIjKL0";
        String testString = "a0bb";

        int startIndex = 0, endIndex = 0;
        int previousUpperCaseIndex = -1;
        int maxLen = 0;

        for (; endIndex < testString.length(); endIndex++) {
            if (Character.isUpperCase(testString.charAt(endIndex))) {
                if (previousUpperCaseIndex > -1) {
                    maxLen = Math.max(maxLen, endIndex - startIndex);
                    startIndex = previousUpperCaseIndex + 1;
                }
                previousUpperCaseIndex = endIndex;
            } else if (Character.isDigit(testString.charAt(endIndex))) {
                if (previousUpperCaseIndex > -1) {
                    maxLen = Math.max(maxLen, endIndex - startIndex);
                }
                startIndex = endIndex + 1;
                previousUpperCaseIndex = -1;
            }
        }
        if (previousUpperCaseIndex > -1)
            maxLen = Math.max(maxLen, endIndex - startIndex);
        System.out.println(maxLen);
    }}

答案 8 :(得分:0)

这是一个动态编程问题。您可以使用矩阵自行解决此问题。这很容易。试一试吧。将密码的字符作为矩阵的行和列。如果附加到最后一个字符的当前字符形成有效密码,请添加对角线。以最小的有效密码作为初始条件开始。

答案 9 :(得分:0)

String[] s = testString.split("[0-9]");
int length = 0;
int index = -1;
for(int i=0; i< s.length; i++){
    if(s[i].matches("[a-z]*.*[A-Z].*[a-z]*")){
        if(length <= s[i].length()){
            length = s[i].length();
            index = i;
        }
    }
}
if(index >= 0){
    System.out.println(s[index]);
}

答案 10 :(得分:0)

在Scala中使用尾递归的另一种解决方案

    def solution2(str: String): Int = {

    val subSt = new ListBuffer[Char]

       def checker(str: String): Unit = {
          if (str.nonEmpty) {
        val s = str.head
        if (!s.isDigit) {
          subSt += s
        } else {
          subSt += '-'
        }
        checker(str.tail)
      }
    }

    checker(str)

    if (subSt.nonEmpty) {
      val noDigitStr = subSt.mkString.split("-")
      Try(noDigitStr.filter(s => s.nonEmpty && s.find(_.isUpper).isDefined).maxBy(_.size))
        .toOption
        .map(_.length)
        .getOrElse(-1)
    } else {
      -1
    }
  }

答案 11 :(得分:0)

这是一个使用Scala的简单解决方案

 def solution(str: String): Int = {
      val strNoDigit = str.replaceAll("[0-9]", "-")
      strAlphas = strNoDigit.split("-")

      Try(strAlphas.filter(_.trim.find(_.isUpper).isDefined).maxBy(_.size))
      .toOption
      .map(_.length)
      .getOrElse(-1)
  }

答案 12 :(得分:0)

public String pass(String str){
    int length = 0;
    boolean uppercase = false;
    String s= "";

    String d= "";

    for(int i=0;i<str.length();i++){
        if(Character.isUpperCase(str.charAt(i)) == true){
        uppercase = true;
        s = s+str.charAt(i);

        }else if(Character.isDigit(str.charAt(i)) == true ){
            if(uppercase == true && s.length()>length){
            d = s;
            s = "";   
            length = s.length();
            uppercase = false;   
            }   
        }else if(i==str.length()-1&&Character.isDigit(str.charAt(i))==false){
        s = s + str.charAt(i);
        if(uppercase == true && s.length()>length){
            d = s;
            s = "";   
            length = s.length();
           uppercase = false;
        }


        }else{
        s = s+str.charAt(i);
        }
   }
  return d;}

答案 13 :(得分:0)

我使用StreamsOptionals

public static String getBestPassword(String password) throws Exception {
    if (password == null) {
        throw new Exception("Invalid password");
    }
    Optional<String> bestPassword = Stream.of(password.split("[0-9]"))
            .filter(TypeErasure::containsCapital)
            .sorted((o1, o2) -> o1.length() > o2.length() ? 1 : 0)
            .findFirst();

    if (bestPassword.isPresent()) {
        return bestPassword.get();
    } else {
        throw new Exception("No valid password");
    }
}

/**
 * Returns true if word contains capital
 */
private static boolean containsCapital(String word) {
    return word.chars().anyMatch(Character::isUpperCase);
}

务必写一些单元测试

答案 14 :(得分:0)

这里有很多好的答案,但认为添加一个使用Java 8流的可能是有意义的:

IntStream.range(0, s.length()).boxed()
    .flatMap(b -> IntStream.range(b + 1, s.length())
        .mapToObj(e -> s.substring(b, e)))
    .filter(t -> t.codePoints().noneMatch(Character::isDigit))
    .filter(t -> t.codePoints().filter(Character::isUpperCase).count() == 1)
    .mapToInt(String::length).max();

如果你想要字符串(而不仅仅是长度),那么最后一行可以替换为:

    .max(Comparator.comparingInt(String::length));

返回Optional<String>

答案 15 :(得分:0)

您不需要正则表达式。只需使用几个整数作为字符串的索引指针:

int i = 0;
int longestStart = 0;
int longestEnd = 0;
while (i < s.length()) {
  // Skip past all the digits.
  while (i < s.length() && Character.isDigit(s.charAt(i))) {
    ++i;
  }

  // i now points to the start of a substring
  // or one past the end of the string.
  int start = i;

  // Keep a flag to record if there is an uppercase character.
  boolean hasUppercase = false;

  // Increment i until you hit another digit or the end of the string.
  while (i < s.length() && !Character.isDigit(s.charAt(i))) {
    hasUppercase |= Character.isUpperCase(s.charAt(i));
    ++i;
  }

  // Check if this is longer than the longest so far.
  if (hasUppercase && i - start > longestEnd - longestStart) {
    longestEnd = i;
    longestStart = start;
  }
}
String longest = s.substring(longestStart, longestEnd);

Ideone demo

虽然比正则表达式更冗长,但这样做的好处是不会创建任何不必要的对象:创建的唯一对象是最长的字符串,最后一个。

答案 16 :(得分:0)

我正在使用Kadane算法的修改来搜索所需的密码长度。您可以使用isNumeric()和isCaps()函数或包含内联if语句。我在下面显示了函数。

public boolean isNumeric(char x){
    return (x>='0'&&x<='9');
}
public boolean isCaps(char x){
    return (x>='A'&&x<='Z');
}
public int maxValidPassLen(String a)
{
   int max_so_far = 0, max_ending_here = 0;
   boolean cFlag = false;
   int max_len = 0;
   for (int i = 0; i < a.length(); i++)
   {
       max_ending_here = max_ending_here + 1;
       if (isCaps(a.charAt(i))){
           cFlag = true;
       }
       if (isNumeric(a.charAt(i))){
           max_ending_here = 0;
           cFlag = false;
       }
       else if (max_so_far<max_ending_here){
           max_so_far = max_ending_here;
       }
       if(cFlag&&max_len<max_so_far){
           max_len = max_so_far;
       }
   }
   return max_len;
}

希望这有帮助。