• 编程题总结(未完待续)


      最近学校那边已经结业,在家闲来无事,便开始在牛客网上开始刷题,在线编程的题目有些自己还做不了,不过有些题直接解决以后再看看讨论区大神的答案,只能感慨还有这种操作,所以这篇博客就来记录一下这些神一般的操作。

    1、判断一个数是否是素数

    素数(也叫质数):即只能被1和自己本身整除的数。这里有几种判断方法。

    (1)直接判断法

    根据定义直接判断从2到n-1是否存在n的约数即可。

    public static boolean isPrime(int n){
      for (int i = 2; i < n; i++) {
        if (n % i == 0) {
          return false;
        }
      }
      return true;
    }

     (2)直接判断法改进

      上述的方法,存在效率低的问题,对于一个数n,其实并不需要从2判断到n-1。这里有一个小知识点就是,若一个数可以分解质因数,那么分解得到的两个数一定是一个小于根号n,另一个大于根号n。所以只需判断从2到根号n之间是否存在约数。若根号n左边找不到约数,那么右边一定也找不到。

    public static boolean isPrime(int n){
      for (int i = 2; i < Math.sqrt(n); i++) {
        if (n % i == 0) {
          return false;
        }
      }
      return true;
    }

    (3)6的倍数法

      首先看一下关于质数分布的规律:大于等于5的质数一定和6的倍数相邻。例如5和7,11和13,17和19等。

    证明:令x ≥ 1,将大于等于5的自然数表示如下:

    ... 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 ...

      可以看到不在6的倍数两侧的数,6x+2,6x+3,6x+4,由于2(3x+1),3(2x+1),2(3x+2)一定不是素数,再除去6x本身,即素数只能出现在6x相邻的两侧。但是这个方法不是绝对的,在6的倍数相邻的两侧并不一定就是素数。注意:素数出现在6x两侧 ≠ 6x两侧都是素数

    根据以上规律,判断质数可以以6个为单元快进。

    public static boolean isPrime3(int n){
            //判断较小的数
            if (n == 2 || n == 3) {
                return true;
            }
            //不是6x两侧的数一定不是素数
            if (n % 6 != 1 && n % 6 != 5) {
                return false;
            }
            //在6x两侧是也不一定都是素数
            for (int i = 5; i <= Math.sqrt(n); i+=6) {
                if (n % i == 0 || n % (i+2) == 0) {
                    return false;
                }
            }
            //排除所有,剩下的都是素数
            return true;
            
        }

     

    性能测试:数据量为20W

    public class test {
        public static void main(String[] args) {
            long s1 = System.currentTimeMillis();
            for (int i = 0; i < 200000; i++) {
                isPrime(i);
            }
            long s2 = System.currentTimeMillis();
            System.out.println("第一种方法运行的时间为:"+(s2-s1));
            
            long s3 = System.currentTimeMillis();
            for (int i = 0; i < 200000; i++) {
                isPrime2(i);
            }
            long s4 = System.currentTimeMillis();
            System.out.println("第二种方法运行的时间为:"+(s4-s3));
            
            long s5 = System.currentTimeMillis();
            for (int i = 0; i < 200000; i++) {
                isPrime3(i);
            }
            long s6 = System.currentTimeMillis();
            System.out.println("第三种方法运行的时间为:"+(s6-s5));
            
        }
        //方法一
        public static boolean isPrime(int n){
            for (int i = 2; i < n; i++) {
                if (n % i == 0) {
                    return false;
                }
            }
            return true;
        }
        //方法二
        public static boolean isPrime2(int n){
            for (int i = 2; i < Math.sqrt(n); i++) {
                if (n % i == 0) {
                    return false;
                }
            }
            return true;
        }
        //方法三
        public static boolean isPrime3(int n){
            //判断较小的数
            if (n == 2 || n == 3) {
                return true;
            }
            //不是6x两侧的数一定不是素数
            if (n % 6 != 1 && n % 6 != 5) {
                return false;
            }
            //在6x两侧是也不一定都是素数
            for (int i = 5; i <= Math.sqrt(n); i+=6) {
                if (n % i == 0 || n % (i+2) == 0) {
                    return false;
                }
            }
            //排除所有,剩下的都是素数
            return true;
            
        }
            
    }

    程序运行的结果为:

     2、字符替换

    对于字符串的操作,有一种很便捷的方法就是使用正则表达式,String中也提供了有关正则表达式的方法。

      ①matches(String regex)

      返回boolean,字符串匹配的方法

      ②replaceAll(String regex,String replacement)

      返回String,字符串替换的方法

      ③split(String regex)

      返回String[],字符串拆分的方法。

    例一:删除一串字符中的数字

    public static void main(String[] args) {
        String str = "1s2f3v4s5hj6x7hj8sdr";
        System.out.println(str.replaceAll("\d", ""));
        }

    程序输出的结果是:sfvshjxhjsdr

    正则表达式中d表示的是数字,D表示的是非数字。

    例二:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str1 = in.nextLine();
        String str2 = in.nextLine();
        in.close();
            
        String pattern = "[" + str2 + "]";
        String s = str1.replaceAll(pattern, "");
        System.out.println(s);
        
        }

    例三:将一句话的单词进行倒置,标点不倒置。比如 I like beijing. 经过函数后变为:beijing. like I

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        in.close();
            
        String out = "";
        String[] s = str.split(" ");
        for (int i = s.length-1; i >= 0; i--) {
            out += s[i] + " ";
        }
        System.out.print(out.trim());    
    }

    3、字符串中找出连续最长的数字串

    刚开始见到这个题的时候,我的思路为:

    (1)先将这个字符串进行预处理,根据非数字字符将字符串分割成数字串数组;

    (2)遍历这个数字串数组,比较每个数字串的长度,将最长数字串进行输出。

    代码如下:

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();
        in.close();
        
        String[] n = str.split("\D");
        
        int max = 0;
        String out = "";
        for (int i = 0; i < n.length; i++) {
            if (n[i].length() > max) {
                max = n[i].length();
                out = n[i];
            }
        }
        System.out.println(out);
    }

    运行通过之后,在讨论区见到一种全新的方法,算法思想如下:

    (1)定义一个max表示经过的数字的长度的最大值,count表示计数器,当为字母时重置为0;

    (2)定义end表示数字尾部,每次满足数字时,对max进行判断,当max小于count时,更新max和count;

    (3)最后使用String的substring(begin, end)进行输出,不包括end,从begin取到end - 1。

    public static void main2(String str){
            int max = 0;
            int count = 0;
            int end = 0;
            
            for (int i = 0; i < str.length(); i++) {
                if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
                    count++;
                    if (max < count) {
                        max = count;
                        end = i;
                    }
                }else{
                    count = 0;
                }
            }
            System.out.println(str.substring(end-max+1, end+1));
        }

    4、求n!(即阶乘)末尾有多少个0?

    比如: n = 10; n! = 3628800,所以答案为2。

      刚开始见到这题的时候,就直想着计算阶乘,老老实实计算0的个数,碰到的问题是,n的范围很大,从1到1000,超出了普通类型的最大值,因为之前用过BigInteger这个类,所以就想到用BigInteger来表示阶乘的值。代码如下:

    import java.math.BigInteger;
    import java.util.Scanner;
    
    public class Main9 {
        public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            int n = in.nextInt();
            in.close();
            
            String num = String.valueOf(jiecheng(n));
            char[] c = num.toCharArray();
            
            int count = 0;
            for (int i = c.length-1; i > 0; i--) {
                if (c[i] == '0') {
                    count++;
                }else{
                    break;
                }
            }
            System.out.println(count);
        }
        
        public static BigInteger jiecheng(int i){
            int sum = 1;
            BigInteger bigsum = BigInteger.valueOf(sum);
            for (int j = i; j >0 ; j--) {
                BigInteger bigj = BigInteger.valueOf(j);
                bigsum = bigsum.multiply(bigj);
            }
            return bigsum;
        }
    }

      运行之后,还是通过了检测,但是从感觉这道题肯定不是像我这么解决的,到讨论区一看之后,全是什么分解质因数,计算5的个数,懵了,以为题不对应,看到半天才讨论区的方法才是最简洁的。

    算法思路:

    (1)一个数 n 的阶乘末尾有多少个 0 取决于从 1 到 n 的各个数的因子中 2 和 5 的个数而 2 的个数是远远多余 5 的个数的,因此求出 5 的个数即可;

    (2)求解因子 5 的个数的方法是用 n 不断除以 5,直到结果为 0,然后把中间得到的结果累加. 例如, 100/5 = 20, 20/5 = 4, 4/5 = 0。则 1 到 100 中因子 5 的个数为 (20 + 4 + 0) = 24 个。即 100 的阶乘末尾有 24 个 0。

      其实不断除以 5,是因为每间隔 5 个数有一个数可以被 5 整除, 然后在这些可被 5 整除的数中每间隔 5 个数又有一个可以被 25 整除, 故要再除一次, ... 直到结果为 0, 表示没有能继续被 5 整除的数了。

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        in.close();
            
        int count = 0;
        for (int i = 1; i <= n; i++) {
            int temp = i;
            while (temp%5 == 0) {
                count++;
                temp /= 5;
            }
        }        
        System.out.println(count);
    }

    参考博客

    [1]判断一个数是否为质数/素数——从普通判断算法到高效判断算法思路

    http://blog.csdn.net/huang_miao_xin/article/details/51331710

     

  • 相关阅读:
    C知识(#一些笔记)
    我整理的Python规则(2)
    我整理的Python代码规则
    教你如何通俗易懂的了解深度学习知识
    c#中委托和事件(续)(转)
    c#中的委托和事件(转)
    .Net neatupload上传控件实现文件上传的进度条
    C#常用日期格式处理转换[C#日期格式转换大全
    C#string常用函数总结
    数据库08版本如何移动到05的数据中
  • 原文地址:https://www.cnblogs.com/ghq120/p/8399345.html
Copyright © 2020-2023  润新知