华为OJ


006. 质数因子

题目描述

功能:输入一个正整数,按照从小到大的顺序输出它的所有质数的因子(如180的质数因子为2 2 3 3 5 )。最后一个数后面也要有空格

详细描述:

函数接口说明:
public String getResult(long ulDataInput)
输入参数:
long ulDataInput:输入的正整数
返回值:
String

输入描述:

输入一个long型整数

输出描述:

按照从小到大的顺序输出它的所有质数的因子,以空格隔开。最后一个数后面也要有空格。

输入:

180

输出:

2 2 3 3 5

代码实现:

import java.util.Scanner;

public class Main {
   

    public static void main(String[] args) {
   
        Scanner in = new Scanner(System.in);
        while (in.hasNext()){
   
            long N = in.nextLong();
            Solution(N);
        }
    }

    private static void Solution(long n) {
   
        if(n <= 1){
   
            System.out.println(n);
        }
        int i = 2;
        StringBuilder sb = new StringBuilder();
        while (i <= n){
   
        	// 当 n 能被质数所整除的时候才除以质数
            while (n % i == 0){
   
                sb.append(i).append(" ");
                n /= i;
            }
            i++;
        }
        System.out.println(sb);
    }
}

016. 购物单

题目描述
王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅

        如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

        设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:

v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)

        请你帮助王强设计一个满足要求的购物单。

输入描述:

输入的第 1 行,为两个正整数,用一个空格隔开:N m
(其中 N ( <32000 )表示总钱数, m ( <60 )为希望购买物品的个数。)
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q
(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)

输出描述:

输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值( <200000 )。

输入:

1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0

输出:

2200

问题分析

这道问题比较容易可以看出是一个 0-1 背包问题,只不过它比普通的背包问题复杂一些。因为我们需要对区分出主件和附件,而附件又只有在主件购买的前提下才能购买。

由于每个主件至多有2个附件,所以我们不妨假设每个主件都有两个附件,而对于不存在的附件,直接将价格和重要度置为0即可。

我们设状态方程为 dp[m][n],表示在钱为 n 的条件下,在 m 件商品中获利的最大值。笔者的思路是先挑选主件商品,如果主件商品能够被挑选的话,再决定是否挑选附件。而当我们处理第 m 件主件商品时,我们有以下5种选择,我们需要在比较后选择其中获利最大的方式:

  • 放弃该主件商品,此时 dp[i][j] = dp[i-1][j]
  • 选择该主件商品,但不选择任何附件。
  • 选择该主件商品,并选择附件1。
  • 选择该主件商品,并选择附件2。
  • 选择该主件商品,并选择附件1和附件2。

该题代码如下:

public class Main {
   

    public static void main(String[] args) {
   
        Scanner in = new Scanner(System.in);
        while (in.hasNext()){
   
            int n = in.nextInt();  // 总钱数
            int m = in.nextInt();  // 商品数量
            int[][] v = new int[m+1][3];
            int[][] p = new int[m+1][3];

            for (int i = 1; i <= m; i++){
   
                int a = in.nextInt();   // 价格
                int b = in.nextInt() * a;  // 价格*重要度
                int c = in.nextInt();   // 主附件判断
                if(c == 0){
     // 主件位于 v[i][0] 处
                    v[i][0] = a;
                    p[i][0] = b;
                } else {
     // 商品为附件
                    if(v[c][1] == 0){
   
                        v[c ][1] = a;
                        p[c][1] = b;
                    } else {
   
                        v[c][2] = a;
                        p[c][2] = b;

                    }
                }
            }
            Solution(n, m, v, p);
        }
    }

    private static void Solution(int n, int m, int[][] v, int[][] p) {
   
        int[][] dp = new int[m+1][n+1];
        for (int i = 1; i <= m; i++){
   
            for (int j = 1; j <= n; j++){
   
                int max = dp[i-1][j];
                if(j >= v[i][0]){
   
                    max = Math.max(max, dp[i-1][j-v[i][0]] + p[i][0]);
                }
                if(j >= v[i][0] + v[i][1]){
   
                    max = Math.max(max, dp[i-1][j-v[i][0]-v[i][1]] + p[i][0] + p[i][1]);
                }
                if(j >= v[i][0] + v[i][2]){
   
                    max = Math.max(max, dp[i-1][j-v[i][0]-v[i][2]] + p[i][0] + p[i][2]);
                }
                if(j >= v[i][0] + v[i][1] + v[i][2]){
   
                    max = Math.max(max, dp[i-1][j-v[i][0]-v[i][1]-v[i][2]] + p[i][0] + p[i][1] + p[i][2]);
                }
                dp[i][j] = max;
            }
        }
        System.out.println(dp[m][n]);
    }

}

个人觉得这道题的思路是没啥问题的,但是在牛客网的测试中不能AC,只能通过80%,没找出是啥原因,希望有知道的人告知,非常感谢~


020. 密码验证合格程序

题目描述

密码要求:

1.长度超过8位

2.包括大小写字母.数字.其它符号,以上四种至少三种

3.不能有相同长度超2的子串重复

说明:长度超过2的子串

输入描述:

一组或多组长度超过2的子符串。每组占一行

输出描述:

如果符合要求输出:OK,否则输出NG

输入

021Abc9000
021Abc9Abc1
021ABC9000
021$bc9000

输出

OK
NG
NG
OK

问题分析

这道题靠分步验证即可比较容易地得出结果,最为棘手的验证明显就是密码要求的第三点:不能有相同长度超2的子串重复了。从这里我们应当意识到,如果有长度超过2的子串重复,那么肯定也就存在长度为2的子串重复。所以问题也就转化为了检查字符串中是否存在长度为2的子串重复,这里我们用 String#contains 方法可以轻松地解决该问题。代码如下:

public class Main {
   

    public static void main(String[] args) {
   
        Scanner in = new Scanner(System.in);
        while (in.hasNext()){
   
            String pwd = in.next();
            pwdValidate(pwd);
        }
    }

    public static void pwdValidate(String pwd){
   
        // 1.密码长度必须超过8
        if(pwd == null || pwd.length() < 9){
   
            System.out.println("NG");
            return;
        }
        int[] kind = new int[4];
        // 2. 密码需要存在3种以上的字符类型
        for (int i = 0; i < pwd.length(); i++){
   
            char c = pwd.charAt(i);
            if(c >= 'a' && c <= 'z'){
   
                kind[0] = 1;
            } else if(c >= 'A' && c <= 'Z'){
   
                kind[1] = 1;
            } else if(c >= '0' && c <= '9'){
   
                kind[2] = 1;
            } else {
   
                kind[3] = 1;
            }
        }
        if(kind[0] + kind[1] + kind[2] + kind[3] < 3){
   
            System.out.println("NG");
            return;
        }
        // 3. 密码中不能存在长度超2的重复子串
        for (int i = 0; i < pwd.length()-3; i++){
   
            String sub1 = pwd.substring(i, i+3);
            String sub2 = pwd.substring(i+3);
            if(sub2.contains(sub1)){
   
                System.out.println("NG");
                return;
            }
        }
        System.out.println("OK");
    }
}

023. 删除字符串中出现次数最少的字符

题目描述

实现删除字符串中出现次数最少的字符,若多个字符出现次数一样,则都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。

输入描述:

字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。

输出描述:

删除字符串中出现次数最少的字符后的字符串。

输入

abcdd

输出

dd

问题分析

这道题最简单的做法就是用一个 Map 来存储字符然后找出次数最小的字符逐一删除,代码如下:

public class Main {
   

    public static void main(String[] args) {
   
        Scanner in = new Scanner(System.in);
        while (in.hasNext()){
   
            String s = in.next();
            Solution(s);
        }
    }

    public static void Solution(String s){
   
        if(checkValidate(s)){
   
            return;
        }
        // 储存字符,value为字符出现的次数
        HashMap<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < s.
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值