【问题标题】:Java: Find the longest substring without any number and at least one upper case characterJava:查找没有任何数字且至少有一个大写字符的最长子字符串
【发布时间】:2017-01-16 05:54:14
【问题描述】:

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

您需要为电子邮件定义一个有效的密码,但唯一的 限制是:

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

  • 密码不能有数字

    现在,给定一个字符串,找出最长的子字符串的长度 是一个有效的密码。例如 Input Str = "a0Ba" ,输出应该 be 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;
}

【问题讨论】:

  • 如果您想以优雅的方式进行操作,请使用regex。在谷歌上搜索Pattern.matches() 和正则表达式。

标签: java string algorithm data-structures


【解决方案1】:

怎么样

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 -&gt; s.matches("(.+)?[A-Z](.+)?")) 仅将至少包含一个大写字母的字符串保存到流中。

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

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

.orElse("") 如果没有找到字符串,则返回一个空字符串。

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

【讨论】:

  • 可读性级别 9999999 (y) :)
  • 您能解释一下这里发生了什么吗?
  • 但是对于字符串a0bb,它应该返回-1。
  • @roger_that 为什么会这样?长度怎么可能是-1?
  • @Gabriel:是的,我的错。我本来应该放一张空支票以返回 -1 作为要求。
【解决方案2】:

我建议你将你的字符串拆分成一个没有数字的字符串数组:

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

然后遍历这个数组(比如数组a)以获得包含一个大写字符的最长字符串:

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

【讨论】:

    【解决方案3】:

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

    算法应该如下:

    跟踪 char 数组的 2 个索引。这2个索引在这里分别称为front和back,分别代表数组的前后。

    有一个int(我在这里将其命名为up)来跟踪大写char的数量。

    全部设为 0。

    如果front &gt; N,其中N 是给定的char 的数量,则使用while 循环终止。

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

    如果up 至少为 1,则根据需要更新最大长度。

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

    输出最大长度。

    【讨论】:

      【解决方案4】:

      您可以使用我的解决方案,该解决方案在 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));
      

      【讨论】:

      • 您或许应该查看java.lang.Character 的Javadoc。有一大堆isSomething 方法,例如isUpperCase,比你的isCharUpperCase 方法使用起来更方便快捷;和isDigit,它涵盖了比0-9更广泛的数字范围。另外,if (condition) return true; else return false; 与 return condition; 相同。
      • 非常感谢@AndyTurner,布尔 if-else 结构是我的错,我每次都这样做,现在更新了 :)。每次构建项目时,我总是会遇到字符问题,因此想通过使用我之前使用的正则表达式文字来使用通用大写字母查找器,而且您对这些数字也是正确的,我将更新该部分,再次感谢 :) 你知道,这里最重要的是迭代中的算法;)
      【解决方案5】:

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

      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

      虽然比正则表达式更冗长,但它的优点是不会创建任何不必要的对象:唯一创建的对象是最长的字符串,就在末尾。

      【讨论】:

      • 你是如何放置“Ideone 演示”按钮的?
      • 使用&lt;kbd&gt;&lt;/kbd&gt; 标签。
      • 感谢您的回答
      【解决方案6】:

      我正在使用 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;
      }
      

      希望这会有所帮助。

      【讨论】:

      • 注意:在与int 比较之前,您不需要强制转换char:它会自动加宽。此外,您可以使用'0' 和'9' 代替48 和57;它只是清楚地说明了这些神奇的数字是什么。 if (condition) return true; return false; 也与 return condition; 相同。
      【解决方案7】:

      这里有很多很好的答案,但认为添加一个使用 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&lt;String&gt;。

      【讨论】:

        【解决方案8】:

        我会使用Streams 和Optionals:

        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);
        }
        

        一定要写一些单元测试

        【讨论】:

          【解决方案9】:
          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;}
          

          【讨论】:

            【解决方案10】:

            这是一个使用 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)
              }
            

            【讨论】:

              【解决方案11】:

              在 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
                  }
                }
              

              【讨论】:

                【解决方案12】:

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

                【讨论】:

                  【解决方案13】:
                  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]);
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    //最简单的方法:

                    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));
                    

                    【讨论】:

                      【解决方案15】:

                      这是我使用 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;
                              }
                      
                          }
                      

                      【讨论】:

                        【解决方案16】:

                        我认为这个解决方案可以解决所有可能的极端情况。它通过了在线法官中的所有测试用例。是动态滑动窗口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);
                            }}
                        

                        【讨论】:

                        • @roger_我最多解决了 1 个大写字符。我现在检查了这个问题。我会据此修改代码。
                        • 谢谢 roger_that。我修改了我的代码。如果有更多测试用例失败,请告诉我。
                        【解决方案17】:
                        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;
                            }
                        }
                        

                        【讨论】:

                          猜你喜欢
                          • 2018-05-08
                          • 2012-01-11
                          • 2020-06-05
                          • 2012-06-05
                          • 2021-12-11
                          • 1970-01-01
                          • 2014-11-09
                          • 2013-06-09
                          • 1970-01-01
                          相关资源
                          最近更新 更多