收录问题
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 ,则所求的总和为:
请你帮助王强设计一个满足要求的购物单。
输入描述:
输入的第 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.