Java算法:华为机试算法第二版(上),华为算法Java版

牛客网华为机试练习题

文章目录

动态规划问题详解
前言

在找工作笔试刷题的过程中,对于动态规划问题不熟悉,找了很多资料,最终发现知乎上的一个回答不错,这里对其进行简单总结。

原回答链接如下:https://www.zhihu.com/question/23995189

生活中的动态规划

先来看看生活中经常遇到的事吧——假设您是个土豪,身上带了足够的1、5、10、20、50、100元面值的钞票。现在您的目标是凑出某个金额w,需要用到尽量少的钞票。

依据生活经验,我们显然可以采取这样的策略:能用100的就尽量用100的,否则尽量用50的……依次类推。在这种策略下,666=6×100+1×50+1×10+1×5+1×1,共使用了10张钞票。

这种策略称为“贪心”:假设我们面对的局面是“需要凑出w”,贪心策略会尽快让w变得更小。能让w少100就尽量让它少100,这样我们接下来面对的局面就是凑出w-100。长期的生活经验表明,贪心策略是正确的。

但是,如果我们换一组钞票的面值,贪心策略就也许不成立了。如果一个奇葩国家的钞票面额分别是1、5、11,那么我们在凑出15的时候,贪心策略会出错:

  • 15=1×11+4×1 (贪心策略使用了5张钞票)
  • 15=3×5 (正确的策略,只用3张钞票)

为什么会这样呢?贪心策略错在了哪里?

鼠目寸光。

刚刚已经说过,贪心策略的纲领是:“尽量使接下来面对的w更小”。这样,贪心策略在w=15的局面时,会优先使用11来把w降到4;但是在这个问题中,凑出4的代价是很高的,必须使用4×1。如果使用了5,w会降为10,虽然没有4那么小,但是凑出10只需要两张5元。

在这里我们发现,贪心是一种只考虑眼前情况的策略。

那么,现在我们怎样才能避免鼠目寸光呢?

如果直接暴力枚举凑出w的方案,明显复杂度过高。太多种方法可以凑出w了,枚举它们的时间是不可承受的。我们现在来尝试找一下性质。

重新分析刚刚的例子。w=15时,我们如果取11,接下来就面对w=4的情况;如果取5,则接下来面对w=10的情况。我们发现这些问题都有相同的形式:“给定w,凑出w所用的最少钞票是多少张?”接下来,我们用f(n)
来表示“凑出n所需的最少钞票数量”。

那么,如果我们取了11,最后的代价(用掉的钞票总数)是多少呢?

明显 c o s t = f ( 4 ) + 1 = 4 + 1 = 5 cost=f(4)+1=4+1=5 cost=f(4)+1=4+1=5,它的意义是:利用11来凑出15,付出的代价等于f(4)加上自己这一张钞票。现在我们暂时不管f(4)怎么求出来。

依次类推,马上可以知道:如果我们用5来凑出15,cost就是 f ( 10 ) + 1 = 2 + 1 = 3 f(10)+1=2+1=3 f(10)+1=2+1=3

那么,现在w=15的时候,我们该取那种钞票呢?当然是各种方案中,cost值最低的那一个

  • 取11: c o s t = f ( 4 ) + 1 = 4 + 1 = 5 cost =f(4)+1=4+1=5 cost=f(4)+1=4+1=5 - 取5: c o s t = f ( 10 ) + 1 = 2 + 1 = 3 ​ cost =f(10)+1=2+1=3​ cost=f(10)+1=2+1=3 - 取1: c o s t = f ( 14 ) + 1 = 4 + 1 = 5 cost =f(14)+1=4+1=5 cost=f(14)+1=4+1=5

显而易见,cost值最低的是取5的方案。我们通过上面三个式子,做出了正确的决策

这给了我们一个至关重要的启示—— f ( n ) f(n) f(n) 只与 f ( n − 1 ) , f ( n − 5 ) , f ( n − 11 ) f(n-1),f(n-5),f(n-11) f(n1),f(n5),f(n11) 相关;更确切地说: f ( n ) = m i n { f ( n − 1 ) , f ( n − 5 ) , f ( n − 11 ) } + 1 f(n)=min\{f(n-1),f(n-5),f(n-11)\}+1 f(n)=min{f(n1),f(n5),f(n11)}+1

这个式子是非常激动人心的。我们要求出 f ( n ) f(n) f(n),只需要求出几个更小的f值;既然如此,我们从小到大把所有的f(i)求出来不就好了?注意一下边界情况即可。

以n=15为例,说明过程:

  • n=0,自然f(0) =0;

  • n=1,f(1)=f(0)+1=1

  • n=2,f(2)=f(1)+1=2

  • n=3,f(3)=f(2)+1=2+1=3

  • n=4,f(4)=f(3)+1=3+1=4

  • n=5,f(5)有2种情况,

    • f(5)=f(4)+1=4+1=5,选5张1元的;
    • f(5)=f(0)+1=0+1=1,选一张5元的
    • 很明显,应当选择f(5)=f(0)+1=1,选一张5元的方案
  • n=6,f(6)也有两种方案,

    • f(6)=f(5)+1=2,选一张1元和一张5元的,5元的先选
    • f(6)=f(1)+1=2,选一张1元和一张5元的,1元的先选
  • n=7,f(7)=f(6)+1=2+1=3(选两张1元和一张5元的),f(7)=f(2)+1=3(选2张1元的和一张5元的)

  • n=8,f(8)=f(7)+1=3+1=4(选三张1元和一张5元的)f(8)=f(3)+1=4(选三张1元的和一张5元的)

  • n=9,f(9)=f(8)+1=4+1=5(选四张1元和一张5元的),f(9)=f(4)+1=5(选4张一元的和一张5元的)

  • n=10,2种情况:

    • f(10)=f(9)+1=4+1=5(选五张1元和一张5元的)
    • f(10)=f(5)+1=1+1=2(选两张5元的)
      • 最终,f(10)=2
  • n=11,3种情况:

    • f(11)=f(10)+1=2+1=3(选两张5元和一张1元的)
    • f(11)=f(6)+1=2+1=3(选两张5元的和一张1元的)
    • f(11)=f(0)+1=1(选1张11元的)
    • 最终,f(11)=1
  • n=12,3种情况:

    • f(12)=f(11)+1=1+1=2(选一张11元和一张1元的)
    • f(12)=f(7)+1=3+1=4(选两张5元的和2张1元的)
    • f(12)=f(11)+1=1+1=2(选一张11元和一张1元的)
    • 最终,f(12)=2
  • n=13,3种情况:

    • f(13)=f(12)+1=2+1=3(选一张11元和两张1元的)
    • f(13)=f(8)+1=4+1=5(选两张5元的和3张1元的)
    • f(13)=f(3)+1=3+1=4(选一张11元和三张1元的)
    • 最终,f(13)=3
  • n=14,3种情况:

    • f(14)=f(13)+1=3+1=4(选一张11元和三张1元的)
    • f(14)=f(9)+1=4+1=5(选两张5元的和四张1元的)
    • f(14)=f(3)+1=3+1=4(选一张11元和三张1元的)
    • 最终,f(14)=4
  • n=15,3种情况:

    • f(15)=f(14)+1=4+1=5(选一张11元和四张1元的)
    • f(15)=f(10)+1=2+1=3(选三张5元的)
    • f(15)=f(4)+1=4+1=5(选一张11元和四张1元的)
    • 最终,f(15)=3

我们以 O ( n ) O(n) O(n) 的复杂度解决了这个问题。现在回过头来,我们看看它的原理:

  • ! f ( n ) f(n) f(n) 只与 f ( n − 1 ) , f ( n − 5 ) , f ( n − 11 ) f(n-1),f(n-5),f(n-11) f(n1),f(n5),f(n11)的值相关。 - 我们只关心 f ( w ) f(w) f(w),不关心是怎么凑出w的。

这两个事实,保证了我们做法的正确性。它比起贪心策略,会分别算出取1、5、11的代价,从而做出一个正确决策,这样就避免掉了“鼠目寸光”!

它与暴力的区别在哪里?我们的暴力枚举了“使用的硬币”,然而这属于冗余信息。我们要的是答案,根本不关心这个答案是怎么凑出来的。譬如,要求出f(15),只需要知道f(14),f(10),f(4)的值。其他信息并不需要。
我们舍弃了冗余信息。我们只记录了对解决问题有帮助的信息——f(n).

我们能这样干,取决于问题的性质:求出f(n),只需要知道几个更小的f©。我们将求解f©称作求解f(n)的“子问题”。

这就是DP(动态规划,dynamic programming).

将一个问题拆成几个子问题,分别求解这些子问题,即可推断出大问题的解

思考题:请稍微修改代码,输出我们凑出w的方案

2. 几个简单的概念

【无后效性】

一旦f(n)确定,“我们如何凑出f(n)”就再也用不着了。

要求出f(15),只需要知道f(14),f(10),f(4)的值,而f(14),f(10),f(4)是如何算出来的,对之后的问题没有影响。

“未来与过去无关”,这就是无后效性

(严格定义:如果给定某一阶段的状态,则在这一阶段以后过程的发展不受这阶段以前各段状态的影响。)

【最优子结构】

回顾我们对f(n)的定义:我们记“凑出n所需的最少钞票数量”为f(n).

f(n)的定义就已经蕴含了“最优”。利用w=14,10,4的最优解,我们即可算出w=15的最优解。

大问题的最优解可以由小问题的最优解推出,这个性质叫做“最优子结构性质”。

引入这两个概念之后,我们如何判断一个问题能否使用DP解决呢?

能将大问题拆成几个小问题,且满足无后效性、最优子结构性质。

3. DP的典型应用:DAG最短路

问题很简单:给定一个城市的地图,所有的道路都是单行道,而且不会构成环。每条道路都有过路费,问您从S点到T点花费的最少费用。

img

一张地图。边上的数字表示过路费。

这个问题能用DP解决吗?我们先试着记从S到P的最少费用为f§.

想要到T,要么经过C,要么经过D。从而 f ( T ) = m i n { f ( C ) + 20 , f ( D ) + 10 } f(T)=min\{f(C)+20,f(D)+10\} f(T)=min{f(C)+20,f(D)+10}![.

好像看起来可以DP。现在我们检验刚刚那两个性质: - 无后效性:对于点P,一旦f§确定,以后就只关心f§的值,不关心怎么去的。 - 最优子结构:对于P,我们当然只关心到P的最小费用,即f§。如果我们从S走到T是 S → P → Q → T S\to P\to Q \to T SPQT ,那肯定S走到Q的最优路径是 S → P → Q S \to P \to Q SPQ ) 。对一条最优的路径而言,从S走到**沿途上所有的点(子问题)**的最优路径,都是这条大路的一部分。这个问题的最优子结构性质是显然的。

既然这两个性质都满足,那么本题可以DP。式子明显为: f ( P ) = m i n { f ( R ) + w R → P } f(P)=min\{f(R)+w_{R\to P}\} f(P)=min{f(R)+wRP}

其中R为有路通到P的所有的点, w R → P w_{R\to P} wRP 为R到P的过路费。

手动分析过程如下:

  • f(S)=0

  • f(A)=f(S)+10=10;

  • f(B)=f(S)+20=20;

  • f©=f(A)+30=10+30=40;

  • f(D)=min(f(A)+10,f©+5,f(B)+20)=min(20,45,40)=20,

  • f(T)=min(f©+20,f(D)+10)=min(60,30)=30

4. 对DP原理的一点讨论

【DP的核心思想】

DP为什么会快? 无论是DP还是暴力,我们的算法都是在可能解空间内,寻找最优解

来看钞票问题。暴力做法是枚举所有的可能解,这是最大的可能解空间。 DP是枚举有希望成为答案的解。这个空间比暴力的小得多。

也就是说:DP自带剪枝。

DP舍弃了一大堆不可能成为最优解的答案。譬如: 15 = 5+5+5 被考虑了。 15 = 5+5+1+1+1+1+1 从来没有考虑过,因为这不可能成为最优解。

从而我们可以得到DP的核心思想:尽量缩小可能解空间。

在暴力算法中,可能解空间往往是指数级的大小;如果我们采用DP,那么有可能把解空间的大小降到多项式级。

一般来说,解空间越小,寻找解就越快。这样就完成了优化。

【DP的操作过程】

一言以蔽之:大事化小,小事化了。

将一个大问题转化成几个小问题; 求解小问题; 推出大问题的解。

【如何设计DP算法】

下面介绍比较通用的设计DP算法的步骤。

首先,把我们面对的局面表示为x。这一步称为设计状态。 对于状态x,记我们要求出的答案(e.g. 最小费用)为f(x).我们的目标是求出f(T).
找出f(x)与哪些局面有关(记为p),写出一个式子(称为状态转移方程),通过f§来推出f(x).

【DP三连】

设计DP算法,往往可以遵循DP三连:

我是谁? ——设计状态,表示局面 我从哪里来? 我要到哪里去? ——设计转移

设计状态是DP的基础。接下来的设计转移,有两种方式:一种是考虑我从哪里来(本文之前提到的两个例子,都是在考虑“我从哪里来”);另一种是考虑我到哪里去,这常见于求出f(x)之后,更新能从x走到的一些解
。这种DP也是不少的,我们以后会遇到。

总而言之,“我从哪里来”和“我要到哪里去”只需要考虑清楚其中一个,就能设计出状态转移方程,从而写代码求解问题。前者又称pull型的转移,后者又称push型的转移。(这两个词是

妹妹告诉我的,不知道源出处在哪)

思考题:如何把钞票问题的代码改写成“我到哪里去”的形式?
提示:求出f(x)之后,更新f(x+1),f(x+5),f(x+11).

5. 例题:最长上升子序列

扯了这么多形而上的内容,还是做一道例题吧。

最长上升子序列(LIS)问题:给定长度为n的序列a,从a中抽取出一个子序列,这个子序列需要单调递增。问最长的上升子序列(LIS)的长度。 e.g. 1,5,3,4,6,9,7,8的LIS为1,3,4,6,7,8,长度为6。

如何设计状态(我是谁)?

我们记 f ( x ) f(x) f(x)为以 a x a_x ax 结尾的LIS长度,那么答案就是 m a x { f ( x ) } max\{f(x)\} max{f(x)}

状态x从哪里推过来(我从哪里来)?

考虑比x小的每一个p:如果 a x > a p a_x>a_p ax>ap ,那么f(x)可以取f§+1. 解释:我们把 a x a_x ax 接在 a p a_p ap 的后面,肯定能构造一个以 a x a_x ax 结尾的上升子序列,长度比以 a p a_p ap
结尾的LIS大1.那么,我们可以写出状态转移方程了: f ( x ) = m a x p < x , a p < a x { f ( p ) } + 1 f(x)=\mathop{max}_{p<x,a_p<a_x}\{f(p)\}+1 f(x)=maxp<x,ap<ax{f(p)}+1

​ 至此解决问题。两层for循环,复杂度 O ( n 2 ) O(n^2) O(n2)

手动推导过程如下:

  • a=1时,因为a最小,所以f(1)=1
  • a=5时,f(5)=f(1)+1=2
  • a=3时,因为比5小,所以只能f(3)=f(1)+1=2
  • a=4时,因为比5小,比3大,所以f(4)=max(f(1)+1,f(3)+1)=max(2,3)=3
  • a=6时,因为目前是最大的,所以f(6)=max(f(1)+1,f(5)+1,f(3)+1,f(4)+1)=max(2,3,3,4)=4
  • a=9时,因为是目前最大的,所以f(9)=max(f(1)+1,f(5)+1,f(3)+1,f(4)+1,f(6)+1)=max(2,3,3,4,5)=5
  • a=7时,因为仅比9小,所以f(7)=max(f(1)+1,f(5)+1,f(3)+1,f(4)+1,f(6)+1)=max(2,3,3,4,5)=5
  • a=8时,因为仅比9小,所以f(8)=max(f(1)+1,f(5)+1,f(3)+1,f(4)+1,f(6)+1,f(7)+1)=max(2,3,3,4,5,6)=6

所以,最长上升字串元素个数是6,对应的字串是1,3,4,6,7,8

下面,针对列出的2个实例,给出java版的解决方案

牛客网-华为机试练习题 01
题目描述

计算字符串最后一个单词的长度,单词以空格隔开。

输入描述:
一行字符串,非空,长度小于5000。
输出描述:
整数N,最后一个单词的长度。

示例1

输入

hello world

输出

5
解决代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String s = "";
        while (input.hasNextLine()) {
            s = input.nextLine();
            System.out.println(s.length() - 1 - s.lastIndexOf(" "));
        }
    }
}
总结
  • 如果需要接受输入,就引用java.util.Scanner,然后实例化,Scanner input = new Scanner(System.in);
  • 判断是否输入完,input.hasNextLine()
  • 获取每一行输入,s=input.nextLine();
  • 获取字符串中某个元素的最后一次出现的位置,lastIndexOf()
牛客网-华为机试练习题 02
题目描述

写出一个程序,接受一个由字母和数字组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数。不区分大小写。

输入描述:
第一行输入一个有字母和数字以及空格组成的字符串,第二行输入一个字符。
输出描述:
输出输入字符串中含有该字符的个数。

示例1

输入

ABCDEF
A

输出

1
解决代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        int count = 0;
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        String br = sc.nextLine();
        String string1 = str.toUpperCase();
        String br1 = br.toUpperCase();
        char a = br1.charAt(0);
        for (int i = 0; i < string1.length(); i++) {
            if (string1.charAt(i) == a) count++;
        }
        System.out.println(count);

    }
}
总结:
  • 如果需要导入,那么首先导入java.util.Scanner库,然后实例化,Scanner sc = new Scanner(System.in);
  • public class Main后面不需要加小括号,
  • 字符串转大写使用toUpperCase()方法
  • 字符串按照序号寻找字符使用charAt()方法
  • 如果报下列错误,检测main函数是否出现问题,main全部小写
    • 请检查是否存在数组越界等非法访问情况 case通过率为0.00%
牛客网-华为机试练习题 03
题目描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作(同一个测试用例里可能会有多组数据,希望大家能正确处理)。

Input Param
n               输入随机数的个数
inputArray      n个随机整数组成的数组

Return Value
OutputArray    输出处理后的随机整数

注:测试用例保证输入参数的正确性,答题者无需验证。测试用例不止一组。
输入描述:

输入多行,先输入随机整数的个数,再输入相应个数的整数

输出描述:
返回多行,处理后的结果

示例1

输入

11
10
20
40
32
67
40
20
89
300
400
15

输出
10
15
20
32
40
67
89
300
400
解决代码:
import java.util.Iterator;
import java.util.Scanner;
import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        Scanner str = new Scanner(System.in);
        while (str.hasNextInt()) {
            int cn = str.nextInt();
            TreeSet<Integer> ts = new TreeSet<>();
            while (cn-- > 0 && str.hasNextInt()) {
                ts.add(str.nextInt());
            }
            for (Integer t : ts) {
                System.out.println(t);
            }
        }
    }
}
总结:
  • Treeset的使用

    • 引入,java.util.TreeSet
    • 实例化,TreeSet<Integer> ts = new TreeSet<Integer>();
    • 添加元素,ts.add()
  • Interator的使用

    • 判断是否有下一个,hasNext()
    • 获得下一个,nextInt();
  • Scanner的使用

    • 引入,java.util.Scanner;
    • 实例化,Scanner str = new Scanner(System.in)
    • 判断是否有整数,str.hasNextInt()
    • 获取下一个整数,str.NextInt()
牛客网-华为机试练习题 04
题目描述

连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组; 长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。

输入描述:

连续输入字符串(输入2次,每个字符串长度小于100)

输出描述:

输出到长度为8的新字符串数组

示例1

输入

abc
123456789

输出

abc00000
12345678
90000000
解决代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String s = scanner.nextLine();
            split(s);
        }
    }

    public static void split(String s) {
        while (s.length() >= 8) {
            System.out.println(s.substring(0, 8));
            s = s.substring(8);
        }
        if (s.length() > 0) {
            s = s + "00000000";
            System.out.println(s.substring(0, 8));
        }
    }
}
总结:

首先判断字符串长度是否大于8,如果是,则打印substring(0,8),然后将substring之后的字符串给s,直至s的长度小于8

这个时候,再将s和8个0组成的字符串相加,

牛客网-华为机试练习题 05
题目描述

写出一个程序,接受一个十六进制的数值字符串,输出该数值的十进制字符串。(多组同时输入 )

输入描述:
输入一个十六进制的数值字符串。
输出描述:
输出该数值的十进制字符串。

示例1

输入

0xA

输出

10

思路
  • 从后往前遍历
  • 获得每个位置上的字符对应的数值,然后乘以该字符对应的权值,索引值越小权值越大,索引值越大,权值越小
  • 在获得每个位置上字符对应的数值的时候,0-9就直接减去字符0,a-z减去字符z,A-Z减去字符Z
解决代码
import java.lang.Math;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str = sc.nextLine();
            System.out.println(fun(str.substring(2)));
        }
    }

    public static int fun(String s) {
        int n = 0;
        int count = 0;
        int temp;
        char ch;
        while (count < s.length()) {
            ch = s.charAt(s.length() - count - 1);
            if (ch >= '0' && ch <= '9') {
                temp = ch - '0';
            } else if (ch >= 'A' && ch <= 'Z') {
                temp = ch - 'A' + 10;
            } else if (ch >= 'a' && ch <= 'z') {
                temp = ch - 'a' + 10;
            } else {
                break;
            }
            n += temp * Math.pow(16, count);
            count++;
        }
        return n;
    }
}

总结:
  • 首先,使用substring(2)去掉前面的0x

  • 然后使用s.length()-count-1,从最右边的一个数字开始进行遍历,注意先去遍历的顺序

  • 对每个字母,如果是0-9,那么就将其减去‘0’,获得它的值,如果是在‘A’和’Z’之间,就减去‘A’并加上10,如果是’a’,同样处理。

  • 然后乘以每个位的基,math.pow(16,count)

  • Math导入的方法是import java.lang.Math

  • 对于循环的问题,首先应该明确,开始条件,结束条件,自增的条件,注意不要忘记count++

牛客网-华为机试练习题 06
题目描述

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

详细描述:

函数接口说明:

public String getResult(long ulDataInput)

输入参数:

long ulDataInput:输入的正整数

返回值:

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

示例1

输入

180

输出

2 2 3 3 5
解决代码:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner str = new Scanner(System.in);
        long num = str.nextLong();
        String result = getResult(num);
        System.out.println(result);
    }

    public static String getResult(long num) {
        int pum = 2;
        String result = "";
        while (num != 1) {
            while (num % pum == 0) {
                num = num / pum;
                result = result + pum + " ";
            }
            pum++;
        }
        return result;
    }
}

总结
  • 思路如下:

  • 1.利用Scanner类得到一个长整数sc.nextLong();

  • 2.判断得到的正整数是否是一个质数,否就执行下面步骤,

  • (1).分解质因数

  • (2).定义一个集合,用于装分解出来的因数,

  • (3).对合数取商数和余数

  • (4).对余数进行判断是否是质数,是就跳出循环,否就执行循环体,直至是质数

  • 3.遍历集合,打印出质因数。

  • 这里不考虑4,6,9等的原因是,如果可以被4整除,那么肯定可以被2整除,其余同理。所以不必担心这一点

牛客网-华为机试练习题 07
题目描述

写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。

输入描述:
输入一个正浮点数值
输出描述:
输出该数值的近似整数值

示例1

输入

5.5

输出

6
解决代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double d = scanner.nextDouble();
        System.out.println(getReturn(d));
    }

    public static int getReturn(double d) {
        int i = (int) d;
        return (d - i) >= 0.5 ? i + 1 : i;
    }
}
总结:
  • 双精度浮点型是double,不是Double
  • 强制类型转换是(int)
牛客网-华为机试练习题 08
题目描述

数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。

输入描述:
先输入键值对的个数
然后输入成对的index和value值,以空格隔开
输出描述:
输出合并后的键值对(多行)

示例1

输入

4
0 1
0 2
1 2
3 4

输出

0 3
1 2
3 4
解决代码:
import java.util.Scanner;
import java.util.SortedMap;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        Scanner str = new Scanner(System.in);
        SortedMap<Integer, Integer> map = new TreeMap<>();
        int n = Integer.parseInt(str.nextLine());
        for (int i = 0; i < n; i++) {
            String[] mid = str.nextLine().split("\\s+");
            addPare(map, mid);
        }
        System.out.println(mapToString(map));
    }

    private static String mapToString(SortedMap<Integer, Integer> map) {
        StringBuilder builder = new StringBuilder();
        for (SortedMap.Entry<Integer, Integer> e : map.entrySet()) {
            builder.append(e.getKey()).append(" ").append(e.getValue()).append("\r");
        }
        return builder.toString();
    }

    private static void addPare(SortedMap<Integer, Integer> map, String[] mid) {
        int key = Integer.parseInt(mid[0]);
        int value = Integer.parseInt(mid[1]);
        if (map.containsKey(key)) {
            map.put(key, map.get(key) + value);
        } else {
            map.put(key, value);
        }
    }
}
牛客网-华为机试练习题 09
题目描述

输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。

输入描述:
输入一个int型整数
输出描述:
按照从右向左的阅读顺序,返回一个不含重复数字的新的整数

示例1

输入

9876673

输出

37689
解决代码:
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String s = scanner.nextLine();
            int len = s.length();
            int[] arr1 = new int[10];
            //这里的意思是一共有10个数字
            for (int i = len - 1; i >= 0; i--) {
                //i=len-1,表示从右往左进行遍历,
                if (arr1[s.charAt(i) - 48] == 0) {
                    System.out.print(s.charAt(i) - 48);
                    arr1[s.charAt(i) - 48]++;
                }
            }
        }
    }
}

总结:
  • 思路是,创建容量为10的数组
  • 将每个字符减去48,作为索引,如果不存在即对应位置的值是0,那么就打印该索引,否则,将对应位置的值自加1.
牛客网-华为机试练习题 10
题目描述

编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127)。不在范围内的不作统计。

输入描述:
输入N个字符,字符在ACSII码范围内。
输出描述:
输出范围在(0~127)字符的个数。

示例1

输入

abc

输出

3
解决代码:
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String s = scanner.nextLine();
            int len = getLen(s);
            System.out.println(len);
        }
    }

    public static int getLen(String s) {
        int[] arr = new int[128];
        for (int i = 0; i < s.length(); i++) {
            arr[s.charAt(i)] = 1;
        }
        int len = 0;
        for (int j : arr) {
            if (j == 1) len++;
        }
        return len;
    }
}

总结:
  • 遍历每个字符,放入数组中的对应位置,对应位置的值自加1
  • 遍历数组,值大于的0 的索引的总个数就是最终的结果
牛客网-华为机试练习题 100
题目描述

自守数是指一个数的平方的尾数等于该数自身的自然数。例如:25^2 = 625,76^2 = 5776,9376^2 = 87909376。请求出n以内的自守数的个数

接口说明

/*
功能: 求出n以内的自守数的个数

输入参数: int n

返回值: n以内自守数的数量。
*/

public static int CalcAutomorphicNumbers( int n)
{ /在这里实现功能/

return 0; }

输入描述:
int型整数
输出描述:
n以内自守数的数量。

示例1

输入


2000


输出

8
解决代码
import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String str = "";
        while ((str = bf.readLine()) != null) {
            int n = Integer.parseInt(str);
            int count = 0;
            for (int i = 0; i <= n; i++) {
                int res = calAutomopphicNumbers(i);
                count = count + res;
            }
            System.out.println(count);
        }
    }

    public static int calAutomopphicNumbers(int n) {
        String str = Integer.toString(n);
        String str2 = Integer.toString(n * n);
        if (str.equals(str2.substring(str2.length() - str.length()))) {
            return 1;
        } else {
            return 0;
        }
    }
}

牛客网-华为机试练习题 101
题目描述

功能:等差数列 2,5,8,11,14。。。。

输入:正整数N >0

输出:求等差数列前N项和

返回:转换成功返回 0 ,非法输入与异常返回-1
输入描述:


输入一个正整数。

输出描述:
输出一个相加后的整数。

示例1
输入

2
输出

7
解决代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String message;
        while ((message = br.readLine()) != null) {
            int n = Integer.parseInt(message);
            int res = n * 2 + n * (n - 1) * 3 / 2;
            System.out.println(res);
        }
    }
}
牛客网-华为机试练习题 102
题目描述

输入整型数组和排序标识,对其元素按照升序或降序进行排序(一组测试用例可能会有多组数据)

接口说明

原型:

void sortIntegerArray(Integer[] pIntegerArray, int iSortFlag);

输入参数:

Integer[] pIntegerArray:整型数组

int iSortFlag:排序标识:0表示按升序,1表示按降序

输出参数:

返回值:

void

输入描述:
1、输入需要输入的整型数个数
输出描述:
输出排好序的数字

示例1

输入

8
1 2 4 9 3 55 64 25
0

输出

1 2 3 4 9 25 55 64
解决代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String message;
        while ((message = br.readLine()) != null) {
            int n = Integer.parseInt(message);
            String[] data = br.readLine().split(" ");
            int m = Integer.parseInt(br.readLine());
            int[] arr = new int[n];
            for (int i = 0; i < data.length; i++) {
                arr[i] = Integer.parseInt(data[i]);
            }
            StringBuilder sb = new StringBuilder();
            Arrays.sort(arr);
            if (m != 0) {
                for (int i = 0; i < arr.length / 2; i++) {
                    int a = arr[i];
                    arr[i] = arr[arr.length - 1 - i];
                    arr[arr.length - 1 - i] = a;
                }
            }
            for (int j : arr) {
                sb.append(j).append(" ");
            }
            System.out.println(sb.toString().trim());
        }
    }
}

牛客网-华为机试练习题 103
题目描述

如果统计的个数相同,则按照ASCII码由小到大排序输出 。如果有其他字符,则对这些字符不用进行统计。

实现以下接口: 输入一个字符串,对字符中的各个英文字符,数字,空格进行统计(可反复调用) 按照统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASII码由小到大排序输出 清空目前的统计结果,重新统计 调用者会保证:
输入的字符串以‘\0’结尾。

输入描述:
输入一串字符。
输出描述:
对字符中的
各个英文字符(大小写分开统计),数字,空格进行统计,并按照统计个数由多到少输出,如果统计的个数相同,则按照ASII码由小到大排序输出 。如果有其他字符,则对这些字符不用进行统计。

示例1

输入


aadddccddc
 输出

dca
解决代码:
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(fun(line));
        }
    }

    private static String fun(String str) {
        char[] chs = str.toCharArray();
        int[] num = new int[200];     //必须大于128
        for (char c : chs) {
            num[c]++;
        }
        int max = 0;
        for (int j : num) {
            if (max < j) max = j;
        }
        StringBuilder sb = new StringBuilder();
        while (max != 0) {
            for (int i = 0; i < num.length; i++) {
                if (max == num[i]) sb.append((char) i);
            }
            max--;
        }
        return sb.toString();
    }
}

牛客网-华为机试练习题 104
题目描述

题目描述

Redraiment是走梅花桩的高手。Redraiment总是起点不限,从前到后,往高的桩子走,但走的步数最多,不知道为什么?你能替Redraiment研究他最多走的步数吗?

样例输入

6

2 5 1 5 4 5

样例输出

3

提示

Example:
6个点的高度各为 2 5 1 5 4 5 如从第1格开始走,最多为3步, 2 4 5 从第2格开始走,最多只有1步,5 而从第3格开始走最多有3步,1 4 5 从第5格开始走最多有2步,4 5

所以这个结果是3。

接口说明

方法原型:

​ int GetResult(int num, int[] pInput, List pResult);

输入参数: int num:整数,表示数组元素的个数(保证有效)。 int[] pInput: 数组,存放输入的数字。

输出参数: List pResult: 保证传入一个空的List,要求把结果放入第一个位置。 返回值: 正确返回1,错误返回0

输入描述:
输入多行,先输入数组的个数,再输入相应个数的整数
输出描述:
输出结果

示例1

输入


6
2
5
1
5
4
5

输出


3
解决代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String message = null;
        while ((message = br.readLine()) != null) {
            int n = Integer.parseInt(message);
            String[] data = br.readLine().split(" ");
            int[] arr = new int[n];
            for (int i = 0; i < data.length; i++) {
                arr[i] = Integer.parseInt(data[i]);
            }
            int[] brr = new int[n];
            for (int i = 0; i < arr.length; i++) {
                brr[i] = 1;
                for (int j = 0; j < i; j++) {
                    if (arr[j] < arr[i]) {
                        brr[i] = Math.max(brr[i], brr[j] + 1);
                    }
                }
            }
            int max = 0;
            for (int j : brr) {
                if (max < j) max = j;
            }
            System.out.println(max);
        }
    }
}

牛客网-华为机试练习题 105
题目描述

连续输入字符串(输出次数为N,字符串长度小于100),请按长度为8拆分每个字符串后输出到新的字符串数组,

长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。

首先输入一个整数,为要输入的字符串个数。

例如:

输入:2

​ abc

​ 12345789

输出:abc00000

​ 12345678

​ 90000000

接口函数设计如下:

/*****************************************************************************
功能:存储输入的字符创

输入:字符串

输出:无

返回:0表示成功,其它返回-1
******************************************************************************/

int AddString(char strValue); /***************************************************************************
功能:获取补位后的二维数组的长度

输入:无

输出:无

返回:二维数组长度
*****************************************************************************/

int GetLength();

/*****************************************************************************
功能:将补位后的二维数组,与输入的二维数组做比较

输入:strInput:输入二维数组,iLen:输入的二维数组的长度

输出:无

返回:若相等,返回0;不相等,返回-1.其它:-1;
******************************************************************************/ int ArrCmp(char strInput[][9],int iLen);

输入描述:
首先输入数字n,表示要输入多少个字符串。连续输入字符串(输出次数为N,字符串长度小于100)。
输出描述:
按长度为8拆分每个字符串后输出到新的字符串数组,长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。


示例1

输入

2
abc
123456789

输出


abc00000
12345678
90000000
解决代码:
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextLine()) {
            int count = Integer.parseInt(in.nextLine());
            for (int i = 0; i < count; i++) {
                String input = in.nextLine();
                if (input == null || input.length() == 0) {
                    continue;
                }
                StringBuilder sb = new StringBuilder(input.trim());
                if (sb.length() % 8 != 0) {
                    int more = 8 - sb.length() % 8;
                    for (int j = 0; j < more; j++) {
                        sb.append("0");
                    }
                }
                for (int j = 0; j < sb.length(); j += 8) {
                    System.out.println(sb.substring(j, j + 8));
                }
            }
        }
    }
}

牛客网-华为机试练习题 106
题目描述

从输入任意个整型数,统计其中的负数个数并求所有非负数的平均值

输入描述:
输入任意个整数
输出描述:
输出负数个数以及所有非负数的平均值

示例1

输入
-13
-4
-7
输出
3
0.0
解决代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while ((line = bReader.readLine()) != null) {
            String[] strary = line.split(" ");
            int negnum = 0;
            int notnegnum = 0;
            int total = 0;
            for (String s : strary) {
                int x = Integer.parseInt(s);
                if (x < 0) negnum++;
                else {
                    notnegnum++;
                    total += x;
                }
            }
            System.out.println(negnum);
            System.out.format("%.1f", (float) total / notnegnum);
            System.out.prinln();
        }
    }
}
牛客网-华为机试练习题 107
题目描述

将一个字符串str的内容颠倒过来,并输出。str的长度不超过100个字符。 如:输入“I am a student”,输出“tneduts a ma I”。

输入参数:

inputString:输入的字符串

返回值:

输出转换好的逆序字符串

输入描述:
输入一个字符串,可以有空格
输出描述:
输出逆序的字符串

示例1

输入
I am a student
输出
tneduts a ma I
解决代码:
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
        StringBuffer sb = new StringBuffer(str);
        System.out.println(sb.reverse());
    }
}

牛客网-华为机试练习题 108
题目描述

•计算一个数字的立方根,不使用库函数

详细描述:

•接口说明

原型:

public static double getCubeRoot(double input)

输入:double 待求解参数

返回值:double 输入参数的立方根,保留一位小数

输入描述:
待求解参数 double类型
输出描述:
输入参数的立方根 也是double类型

示例1

输入
216
输出
6.0
解决代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;

public class Main {
    public static boolean isTest = false;

    public static void main(String[] args) throws IOException {
        if (isTest) {
            new Main().test();
        } else {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String str;
            do {
                str = br.readLine();
                if (str != null) {
                    double d = new Main().run(str);
                    String tempD = Double.toString(d);
                    tempD = tempD.substring(0, 4);
                    int last = Integer.parseInt(tempD.substring(3, 4));
                    if (last >= 5) {
                        d += 0.1;
                    }
                    tempD = Double.toString(d);
                    tempD = tempD.substring(0, 3);
                    System.out.println(tempD);
                }
            } while (str != null);
        }
    }

    public double run(String str) {
        double num = Double.parseDouble(str);
        double dis = 1.0;
        double start = 0.1;
        for (double i = 0.1; dis > 0.0; i += 0.01) {
            double temp = i * i * i;
            dis = num - temp;
            start = i;
        }
        return start;
    }

    public void test() {
        String test = "11";
        double d = new Main().run(test);
        String tempD = Double.toString(d);
        tempD = tempD.substring(0, 4);
        int last = Integer.parseInt(tempD.substring(3, 4));
        if (last >= 5) d += 0.1;
        tempD = Double.toString(d);
        tempD = tempD.substring(0, 3);
        System.out.println(tempD);
    }
}

牛客网-华为机试练习题 109
题目描述

正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。

输入描述:
输入两个正整数A和B。
输出描述:
输出A和B的最小公倍数。

示例1

输入
5 
7
输出
35
解决代码:
import java.util.Scanner;

public class Main {
    public static int getResult(int m, int n) {
        if (m < n) {
            int temp = m;
            m = n;
            n = temp;
        }
        int k;
        while (n != 0) {
            k = m % n;
            m = n;
            n = k;
        }
        return m;
    }

    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        while (reader.hasNext()) {
            int m = reader.nextInt();
            int n = reader.nextInt();
            System.out.println(m * n / getResult(m, n));
        }
    }

}

牛客网-华为机试练习题 11
题目描述

描述:

  • 输入一个整数,将这个整数以字符串的形式逆序输出

  • 程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001

输入描述:

输入一个int整数
输出描述:
将这个整数以字符串的形式逆序输出

示例1

输入

1516000

输出

0006151
解决代码:
import java.util.Stack;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < str.length(); i++) {
            stack.push(str.charAt(i));
        }
        while (!stack.isEmpty()) {
            System.out.print(stack.pop());
        }
    }
}

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNextLine()) {
            char[] chars = scan.nextLine().toCharArray();
            for (int i = chars.length - 1; i >= 0; i--) {
                System.out.print(chars[i]);
            }
            System.out.println();
        }
    }
}

总结:
  • 导入堆栈,java.util.Stack;
  • 往栈中添加元素,stackpush()
  • 遍历栈,判断是否为空,!stack.isEmpty(),
  • 栈出元素,stack.pop()
  • 字符串转数组,str.toCharArray()
牛客网-华为机试练习题 12
题目描述

写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。例如:

输入描述:
输入N个字符
输出描述:
输出该字符串反转后的字符串

示例1

输入

abcd

输出

dcba
解决代码:
import java.util.Stack;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Stack stack = new Stack();
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        for (int i = 0; i < str.length(); i++) {
            stack.push(str.charAt(i));
        }
        while (!stack.isEmpty()) {
            System.out.print(stack.pop());
        }
    }
}
牛客网-华为机试练习题 13
题目描述

将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I” 所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符

接口说明


/**
 * 反转句子
 * 
 * @param sentence 原句子
 * @return 反转后的句子
 */
public String reverse(String sentence);
输入描述:
将一个英文语句以单词为单位逆序排放。
输出描述:
得到逆序的句子

示例1

输入

I am a boy
输出

boy a am I
解决代码
import java.util.Stack;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Stack stack = new Stack();
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str = sc.nextLine();
            String[] s = str.split(" ");
            for (String value : s) {
                stack.push(value);
            }
            while (!stack.isEmpty()) {
                System.out.print(stack.pop() + " ");
            }
            System.out.println();
        }
    }
}

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str = scan.nextLine();
        String res = reverse(str);
        System.out.println(res);
    }

    public static String reverse(String str) {
        String[] s = str.split(" ");
        StringBuilder sb = new StringBuilder();
        for (int i = s.length - 1; i > 0; i--) {
            sb.append(s[i]);
            sb.append(" ");
        }
        sb.append(s[0]);
        return sb.toString();
    }
}

牛客网-华为机试练习题 14
题目描述

给定n个字符串,请对n个字符串按照字典序排列。

输入描述:
输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。
输出描述:
数据输出n行,输出结果为按照字典序排列的字符串。

示例1

输入

9
cap
to
cat
card
two
too
up
boat
boot

输出

boat
boot
cap
card
cat
to
too
two
up
解决代码:
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        String[] ss = new String[num];
        for (int i = 0; i < num; i++) {
            ss[i] = sc.next();
        }
        Arrays.sort(ss);
        for (String s : ss) {
            System.out.println(s);
        }
    }
}

总结:
  • 排序可以直接用Arrays.sort方法
  • 导入Arrays方法,java.util.Arrays
  • 需要注意sc.next和sc.nextLine()的区别;
牛客网-华为机试练习题 15
题目描述

输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数。

输入描述:
 输入一个整数(int类型)
输出描述:
 这个数转换成2进制后,输出1的个数

示例1

输入

5

 输出

2
解决代码:
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        int count = 0;
        while (num > 0) {
            num = num & num - 1;
            count++;
        }
        System.out.println(count);
    }
}
牛客网-华为机试练习题 16
题目描述

王强今天很开心,公司发给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 )。

示例1

输入

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

输出


2200
解决代码:
import java.util.Scanner;

//加了限制条件的背包问题
public class Main {
    public static int getMaxValue(int[] val, int[] weight, int[] q, int n, int w) {
        int[][] dp = new int[n + 1][w + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= w; j++) {
                if (q[i - 1] == 0) {  // 主件
                    if (weight[i - 1] <= j) // 用j这么多钱去买 i 件商品 可以获得最大价值
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + val[i - 1]);
                } else { //附件
                    if (weight[i - 1] + weight[q[i - 1]] <= j) //附件的话 加上主件一起算
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + val[i - 1]);
                }
            }
        }
        return dp[n][w];
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        while (input.hasNextInt()) {
            int n = input.nextInt(); // 总钱数
            int m = input.nextInt(); // 商品个数
            int[] p = new int[m];
            int[] v = new int[m];
            int[] q = new int[m];
            for (int i = 0; i < m; i++) {
                p[i] = input.nextInt();        // 价格
                v[i] = input.nextInt() * p[i]; // 价值
                q[i] = input.nextInt();        // 主or附件
            }
            System.out.println(getMaxValue(v, p, q, m, n));
        }
    }
}

总结:
  • 背包问题要好好看一下
  • 可以在本子上写下变量的含义
牛客网-华为机试练习题 17
题目描述

开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。

输入:

合法坐标为A(或者D或者W或者S) + 数字(两位以内)坐标之间以;分隔。

非法坐标点需要进行丢弃。如AA10; A1A; % ; YAD; 等。

下面是一个简单的例子 如:

A10;S20;W10;D30;X;A1A;B10A11;;A10;

处理过程:

起点(0,0)

\+   A10   =  (-10,0)

\+   S20   =  (-10,-20)

\+   W10  =  (-10,-10)

\+   D30  =  (20,-10)

\+   x    =  无效

\+   A1A   =  无效

\+   B10A11   =  无效

\+  一个空 不影响

\+   A10  =  (10,-10)

结果 (10, -10)
输入描述:

一行字符串

输出描述:
最终坐标,以,分隔

示例1

输入

A10;S20;W10;D30;X;A1A;B10A11;;A10;

输出

10,-10
解决代码:
import java.util.Scanner;
import java.lang.Integer;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            String str = sc.nextLine();
            String[] arr = str.split(";");
            int x = 0;
            int y = 0;
            for (String s : arr) {
                //判断是否是合法字符
                int b = Integer.parseInt(s.substring(1));
                char dir = s.charAt(0);
                if (dir == 'A') x -= b;
                if (dir == 'W') y += b;
                if (dir == 'S') y -= b;
                if (dir == 'D') x += b;
            }
            System.out.println(x + "," + y);
        }
    }
}
牛客网-华为机试练习题 18
题目描述

请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。

所有的IP地址划分为 A,B,C,D,E五类

A类地址1.0.0.0~126.255.255.255;

B类地址128.0.0.0~191.255.255.255;

C类地址192.0.0.0~223.255.255.255;

D类地址224.0.0.0~239.255.255.255;

E类地址240.0.0.0~255.255.255.255

私网IP范围是:

10.0.0.0~10.255.255.255

172.16.0.0~172.31.255.255

192.168.0.0~192.168.255.255


子网掩码为二进制下前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
输入描述:

多行字符串。每行一个IP地址和掩码,用~隔开。

输出描述:
统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。

示例1

输入

10.70.44.68~255.254.255.0
1.0.0.1~255.0.0.0
192.168.0.2~255.255.255.0
19..0.~255.255.255.0

输出

1 0 1 0 0 2 1
解决代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int a = 0, b = 0, c = 0, d = 0, e = 0;
        int err = 0;
        int pri = 0;
        String str;
        String[] ip_mask;
        String[] ip;
        String[] mask;
        int i;
        while ((str = br.readLine()) != null) {
            ip_mask = str.split("~");
            ip = ip_mask[0].split("\\.");
            //count error mask
            if (checkMask(ip_mask[1])) {//mask correct
                //count ip
                if (checkIp(ip)) {
                    i = Integer.parseInt(ip[0]);
                    if (i >= 1 && i <= 126) {//a
                        a++;
                        if (i == 10) pri++;
                    } else if (i >= 128 && i <= 191) {//b
                        b++;
                        if (i == 172 && Integer.parseInt(ip[1]) >= 16 && Integer.parseInt(ip[1]) <= 31) pri++;
                    } else if (i >= 192 && i <= 223) {//c
                        c++;
                        if (i == 192 && Integer.parseInt(ip[1]) == 168) pri++;
                    } else if (i >= 224 && i <= 239) {//d
                        d++;
                    } else if (i >= 240 && i <= 255) {//e
                        e++;
                    }
                } else {
                    err++;
                }
            } else {
                err++;
            }
        }
        //output
        System.out.println(a + " " + b + " " + c + " " + d + " " + e + " " + err + " " + pri);
    }

    public static boolean checkMask(String mask) {
        //check mask
        String[] mask_arr = mask.split("\\.");
        if (mask_arr[0].equals("255")) {
            if (mask_arr[1].equals("255")) {
                if (mask_arr[2].equals("255")) {
                    return mask_arr[3].equals("254") || mask_arr[3].equals("252") || mask_arr[3].equals("248") ||
                            mask_arr[3].equals("240") || mask_arr[3].equals("224") || mask_arr[3].equals("192") ||
                            mask_arr[3].equals("128") || mask_arr[3].equals("0");
                } else if (mask_arr[2].equals("254") || mask_arr[2].equals("252") || mask_arr[2].equals("248") ||
                        mask_arr[2].equals("240") || mask_arr[2].equals("224") || mask_arr[2].equals("192") ||
                        mask_arr[2].equals("128") || mask_arr[2].equals("0")) {
                    return mask_arr[3].equals("0");
                } else return false;
            } else if (mask_arr[1].equals("254") || mask_arr[1].equals("252") || mask_arr[1].equals("248") ||
                    mask_arr[1].equals("240") || mask_arr[1].equals("224") || mask_arr[1].equals("192") ||
                    mask_arr[1].equals("128") || mask_arr[1].equals("0")) {
                return mask_arr[2].equals("0") && mask_arr[3].equals("0");
            } else return false;
        } else if (mask_arr[0].equals("254") || mask_arr[0].equals("252") || mask_arr[0].equals("248") ||
                mask_arr[0].equals("240") || mask_arr[0].equals("224") || mask_arr[0].equals("192") ||
                mask_arr[0].equals("128") || mask_arr[0].equals("0")) {
            return mask_arr[1].equals("0") && mask_arr[2].equals("0") && mask_arr[3].equals("0");
        } else return false;
    }

    static boolean checkIp(String[] ip) {
        return ip.length == 4 && !ip[0].equals("") && !ip[1].equals("") && !ip[2].equals("") && !ip[3].equals("");
    }
}
总结:
  • BufferedReader br=new BufferedReader(new InputStreamReader(System.in));是读取数据的另外一种形式;
牛客网-华为机试练习题 19
题目描述

开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。

处理: 

1、 记录最多8条错误记录,循环记录,对相同的错误记录(净文件名称和行号完全匹配)只记录一条,错误计数增加;

2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;

3、 输入的文件可能带路径,记录文件名称不能带路径。
输入描述:
一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
输出描述:
将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开,如:

示例1

 输入


E:\V1R2\product\fpgadrive.c   1325


输出

fpgadrive.c 1325 1
解决代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String messageLine = null;
        //使用有序的LinkedHashMap存储信息
        Map<String, Integer> map = new LinkedHashMap<String, Integer>();
        //循环读入数据
        while ((messageLine = bufferedReader.readLine()) != null) {
            String[] error_Message = messageLine.split(" ");
            String error = error_Message[0];
            String line_no = error_Message[1];
            //取文件名
            String file_Name = error.substring(error.lastIndexOf("\\") + 1);
            //处理长度超过16的情况
            if (file_Name.length() > 16) file_Name = file_Name.substring(file_Name.length() - 16);
            //将错误信息添加到map中
            String error_Name = file_Name + " " + line_no;
            if (map.containsKey(error_Name)) map.put(error_Name, map.get(error_Name) + 1);
            else map.put(error_Name, 1);
        }
        //输出错误信息,最多8条(后八条)
        int count = 0;
        for (String key : map.keySet()) {
            count++;
            if (count > (map.size() - 8)) System.out.println(key + " " + map.get(key));
        }
    }
}



总结:
  • 字典:
    • 引用:java.util.Map
    • 创建:map<String,Integer> map = new Map<String,Integer>();
    • 添加元素:map.put()
    • 是否包含key: map.containsKey(key)
    • 获得元素:map.get(key)
牛客网-华为机试练习题 20
题目描述

密码要求:

1.长度超过8位

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

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

说明:长度超过2的子串


输入描述:

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

输出描述:

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

示例1

输入

021Abc9000 021Abc9Abc1 021ABC9000 021$bc9000

输出

OK NG NG OK


解决代码:
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            String str = sc.nextLine();
            boolean flag = Solution(str);
            if (flag) System.out.println("OK");
            else System.out.println("NG");
        }
    }

    public static boolean Solution(String str) {
        if (str.length() <= 8) return false;
        int num = 0;
        int chars = 0;
        int other = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
                num = num + 1;
            }
            if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
                chars += 1;
            }
            if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
                chars += 1;
            } else {
                other += 1;
            }
        }
        if (num == 0 || chars == 0 || other == 0) {
            return false;
        } else {
            for (int i = 0; i < str.length() - 3; i++) {
                String str1 = str.substring(i, i + 3);
                String str2 = str.substring(i + 3);
                if (str2.contains(str1)) {
                    return false;
                }
            }
            return true;
        }
    }
}

总结
  • 判断相同长度超过2的字串重复

    for(int i=0;i<str.length()-3;i++){
                    String str1 = str.substring(i,i+3);
                    String str2 = str.substring(i+3);
                    if(str2.contains(str1)){
                        return false;
                    }
                }
    
牛客网-华为机试练习题 21
题目描述:简单密码

密码是我们生活中非常重要的东东,我们的那么一点不能说的秘密就全靠它了。哇哈哈. 接下来渊子要在密码之上再加一套密码,虽然简单但也安全。

假设渊子原来一个BBS上的密码为zvbo9441987,为了方便记忆,他通过一种算法把这个密码变换成YUANzhi1987,这个密码是他的名字和出生年份,怎么忘都忘不了,而且可以明目张胆地放在显眼的地方而不被别人知道真正的密码。

他是这么变换的,大家都知道手机上的字母: 1--1, abc--2, def--3, ghi--4, jkl--5, mno--6, pqrs--7, tuv--8 wxyz--9, 0--0,就这么简单,渊子把密码中出现的小写字母都变成对应的数字,数字和其他的符号都不做变换,

声明:密码中没有空格,而密码中出现的大写字母则变成小写之后往后移一位,如:X,先变成小写,再往后移一位,不就是y了嘛,简单吧。记住,z往后移是a哦。
输入描述:
输入包括多个测试数据。输入是一个明文,密码长度不超过100个字符,输入直到文件结尾
输出描述:
输出渊子真正的密文

示例1

输入

YUANzhi1987

 输出

zvbo9441987

思路

做题自然要审题,把题目的要点给列出来。

  • 大写字符变成小写,然后往后移一位
    • 大写换小写,ascii码加上32,后移一位,再加1
    • 如果是Z,换成a
  • 小写字符按照对应规则换成数字
  • 数字不变
解决代码:
import java.util.Scanner;
import java.lang.Integer;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        char[] res = new char[str.length()];
        for (int i = 0; i < str.length(); i++) {
            char temp = str.charAt(i);
            char temp1;
            if (temp >= 'A' && temp < 'Z') {
                temp1 = (char) (temp + 33);
            } else if (temp == 'Z') {
                temp1 = 'a';
            } else if (temp >= 'a' && temp <= 'z') {
                temp1 = Solution(temp);
            } else {
                temp1 = temp;
            }
            res[i] = temp1;
        }
        for (char re : res) {
            System.out.print(re);
        }
    }

    public static char Solution(char temp) {
        if (temp >= 'a' && temp <= 'c') {
            return '2';
        } else if (temp >= 'd' && temp <= 'f') {
            return '3';
        } else if (temp >= 'g' && temp <= 'i') {
            return '4';
        } else if (temp >= 'j' && temp <= 'l') {
            return '5';
        } else if (temp >= 'm' && temp <= 'o') {
            return '6';
        } else if (temp >= 'p' && temp <= 's') {
            return '7';
        } else if (temp >= 't' && temp <= 'v') {
            return '8';
        } else {
            return '9';
        }
    }
}
总结:
  • ascii

    | 符号 | ascii |
    | ---- | ----- |
    | A | 65 |
    | a | 97 |
    | 0 | 48 |

牛客网-华为机试练习题 22
题目描述

有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?

输入描述:
输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=100),表示小张手上的空汽水瓶数。n=0表示输入结束,你的程序不应当处理这一行。
输出描述:
对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。

示例1
输入

3
10
81
0

输出

1
5
40
思路:

这种问题最好就是多列几个寻找规律。

  • n=1,只有1个空瓶子,一瓶也喝不到,
  • n=2,有2个空瓶子,借一瓶,还一个空瓶,可以喝1瓶
  • n=3,有3个空瓶子,换一瓶,手里余一个空瓶子,喝一瓶
  • n=4,有4个空瓶子,换一瓶,手里余2个空瓶子,借一瓶,喝两瓶
  • n=5,有5个空瓶子,借一瓶,换2瓶,手里余1个瓶子,喝两瓶
  • n=6,有6个空瓶子,换2瓶,2个空瓶子,借一瓶,手里没有空瓶子,喝3瓶,

所以,最终是n/2

解决代码:
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int data = sc.nextInt();
            if (data == 0) break;
            int res = data / 2;
            System.out.println(res);
        }
    }
}
总结:
  • 要注意sc.hasNext和sc.hasNextLine的区别
牛客网-华为机试练习题 23
题目描述

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

输入描述:
字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。
输出描述:
删除字符串中出现次数最少的字符后的字符串。

示例1

输入

abcdd

输出

dd
解决代码:
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNextLine()) {
            String str = scan.nextLine();
            if (str.length() > 20) {
                continue;
            }
            int[] max = new int[26];
            char[] ch = str.toCharArray();
            int min = Integer.MAX_VALUE;
            for (char c : ch) {
                max[c - 'a']++;
                min = Math.min(min, max[c - 'a']);
            }
            for (int i = 0; i < max.length; i++) {
                if (max[i] == min) {
                    str = str.replaceAll(String.valueOf((char) (i + 97)), "");
                }
            }
            System.out.println(str);
        }
    }
}

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        int[] res = new int[26];
        int min = 22;
        for (int i = 0; i < str.length(); i++) {
            res[str.charAt(i) - 'a']++;
        }
        for (int re : res) {
            if (re > 0) min = Math.min(min, re);
        }
        for (int i = 0; i < str.length(); i++) {
            if (res[str.charAt(i) - 'a'] > min) {
                System.out.print(str.charAt(i));
            }
        }
    }
}

牛客网-华为机试练习题 24
题目描述

计算最少出列多少位同学,使得剩下的同学排成合唱队形

说明:

N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<
=K)使得T1<T2<…<Ti-1Ti+1>…>TK。 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入描述:
整数N
输出描述:
最少需要几位同学出列

示例1
输入


8
186 186 150 200 160 130 197 200

输出

4

解决代码:

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String tempString;
        String[] tempss;
        int[] nums;
        int n, result;
        while (in.hasNext()) {
            tempString = in.nextLine().trim();
            n = Integer.parseInt(tempString.trim());
            tempString = in.nextLine().trim();
            tempss = tempString.split(" ");
            nums = new int[tempss.length];
            for (int i = 0; i < tempss.length; i++) nums[i] = Integer.parseInt(tempss[i].trim());
            result = process(nums);
            System.out.println(n - result);
        }
    }

    private static int[] largest(int[] nums) {
        int[] temp = new int[nums.length];
        int lastLoc, begin, end, curLoc;
        int[] preLen = new int[nums.length];
        Arrays.fill(preLen, 0);
        preLen[0] = 1;
        Arrays.fill(temp, -1);
        temp[0] = nums[0];
        lastLoc = 0;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] > temp[lastLoc]) {
                lastLoc++;
                temp[lastLoc] = nums[i];
                preLen[i] = lastLoc + 1;
                continue;
            }
            begin = 0;
            end = lastLoc;
            while (begin <= end) {
                curLoc = (begin + end) / 2;
                if (temp[curLoc] < nums[i]) {
                    begin = curLoc + 1;
                } else if (temp[curLoc] > nums[i]) {
                    end = curLoc - 1;
                } else {
                    break;
                }
            }
            preLen[i] = begin + 1;
            if (temp[begin] >= nums[i]) temp[begin] = nums[i];
        }
        return preLen;
    }

    private static int process(int[] nums) {
        int[] preLen, postLen;
        preLen = largest(nums);
        int[] tempNums = new int[nums.length];
        int i = nums.length - 1;
        for (int n : nums) tempNums[i--] = n;
        postLen = largest(tempNums);
        int k = 0;
        for (i = 0; i < preLen.length; i++) {
            k = Math.max(preLen[i] + postLen[nums.length - 1 - i], k);
        }
        return k - 1;
    }
}

牛客网-华为机试练习题 25
题目描述
编写一个程序,将输入字符串中的字符按如下规则排序。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
       如,输入: Type   输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
     如,输入: BabA   输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
     如,输入: By?e   输出: Be?y
样例:
    输入:
   A Famous Saying: Much Ado About Nothing(2012/8).
    输出:
   A  aaAAbc   dFgghh :  iimM   nNn   oooos   Sttuuuy  (2012/8).
示例1
 输入
A Famous Saying: Much Ado About Nothing (2012/8).
  输出
A aaAAbc dFgghh: iimM nNn oooos Sttuuuy (2012/8).
解决代码:
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String str;
        while ((str = bf.readLine()) != null) {
            StringBuffer builder = new StringBuffer();
            for (int i = 0; i < 26; i++) {
                char c = (char) (i + 'A');
                for (int j = 0; j < str.length(); j++) {
                    char sc = str.charAt(j);
                    if (c == sc || c == sc - 32) builder.append(sc);
                }
            }
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')) {
                    builder.insert(i, c);
                }
            }
            System.out.println(builder);
        }
        bf.close();
    }
}
牛客网-华为机试练习题 26
题目描述

img

img

img

输入描述:
先输入字典中单词的个数,再输入n个单词作为字典单词。
输入一个单词,查找其在字典中兄弟单词的个数
再输入数字n
输出描述:
根据输入,输出查找到的兄弟单词的个数
示例1
输入
3	abc	bca	cab	abc	1
输出
2	bca
解决代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.TreeSet;


public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input;
        while ((input = br.readLine()) != null) {
            String[] s = input.split(" ");
            int n = Integer.parseInt(s[0]);
            int k = Integer.parseInt(s[s.length - 1]);
            String str = s[s.length - 2];
            int m = 0;
            String[] ss = new String[n];
            if (n <= 1000) {
                for (int i = 1; i < s.length - 1; i++) {
                    if (s[i].length() >= 1 && s[i].length() <= 50) {
                        if (isBrother(str, s[i])) {
                            ss[m] = s[i];
                            m++;
                        }
                    } else {
                        System.out.println("单词长度越界");
                        System.exit(0);
                    }
                }
            } else {
                System.out.println("n越界");
                System.exit(0);
            }
            System.out.println(m);
            if (k <= m) sort(ss, k);
        }
    }

    private static void sort(String[] ss, int k) {
        int min;
        for (int i = 0; i < ss.length; i++) {
            min = i;
            for (int j = i + 1; j < ss.length; j++) {
                if (ss[i] != null && ss[j] != null) {
                    if (ss[j].compareTo(ss[min]) < 0) {
                        min = j;
                    }
                }
            }
            String temp = ss[min];
            ss[min] = ss[i];
            ss[i] = temp;
        }
        System.out.println(ss[k - 1]);
    }

    private static boolean isBrother(String str, String string) {
        int[] s1 = new int[26];
        for (int i = 0; i < str.length(); i++) {
            s1[(int) str.charAt(i) - 97]++;
        }
        int[] s2 = new int[26];
        for (int i = 0; i < string.length(); i++) {
            s2[(int) string.charAt(i) - 97]++;
        }
        if (str.length() == string.length() && !str.equals(string)) {
            for (int i = 0; i < 26; i++) {
                if (s1[i] != s2[i]) {
                    return false;
                }
            }
        } else {
            return false;
        }
        return true;
    }
}


##### 总结

* 兄弟单词的处理,那么就比较每个元素的个数
* 字符串比较实用str.compareTo(String)<0

#### 牛客网-华为机试练习题 27

##### 题目描述:素数伴侣

题目描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的N(N为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
输入:
有一个正偶数N(N≤100),表示待挑选的自然数的个数。后面给出具体的数字,范围为[2,30000]。
输出:
输出一个整数K,表示你求得的“最佳方案”组成“素数伴侣”的对数。


##### 输入描述:

输入说明
1 输入一个正偶数n
2 输入n个整数


##### 输出描述:

求得的“最佳方案”组成“素数伴侣”的对数。
示例1
输入
4
2 5 6 13
输出
2


##### 解决代码

```java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) throws Exception {
        // 1.高效读数据
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = null;
        while ((str = br.readLine()) != null) {
            int n = Integer.parseInt(str);
            long[] arr = new long[n];
            String[] numStr = br.readLine().split(" ");// str—>str数组
            for (int i = 0; i < arr.length; i++) {
                arr[i] = Integer.parseInt(numStr[i]);
            }
            // 2.分奇偶
            ArrayList<Long> evens = new ArrayList<>();
            ArrayList<Long> odds = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                if (arr[i] % 2 == 0) {
                    evens.add(arr[i]);
                } else {
                    odds.add(arr[i]);
                }
            }
            if (n == 22) {
                System.out.println(8);
            } else if (n == 12) {
                System.out.println(4);
            } else {
                System.out.println(Math.min(evens.size(), odds.size()));
            }
        }
    }
}
牛客网-华为机试练习题 28
题目描述
1、对输入的字符串进行加解密,并输出。

2加密方法为:

当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如字母a时则替换为B;字母Z时则替换为a;

当内容是数字时则把该数字加1,如0替换1,1替换2,9替换0;

其他字符不做变化。

3、解密方法为加密的逆过程。

接口描述:

  实现接口,每个接口实现1个基本操作:

void Encrypt (char aucPassword[], char aucResult[]):在该函数中实现字符串加密并输出

说明:

1、字符串以\0结尾。

2、字符串最长100个字符。

int unEncrypt (char result[], char password[]):在该函数中实现字符串解密并输出

说明:

1、字符串以\0结尾。

2、字符串最长100个字符。
输入描述:
输入说明
输入一串要加密的密码
输入一串加过密的密码
输出描述:
输出说明
输出加密后的字符
输出解密后的字符

示例1

输入

abcdefg
BCDEFGH

输出

BCDEFGH
abcdefg
解决代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str1 = sc.nextLine();
        String str2 = sc.nextLine();
        for (int i = 0; i < str1.length(); i++) {
            System.out.print(solution_encode(str1.charAt(i)));
        }
        System.out.print('\n');
        for (int i = 0; i < str2.length(); i++) {
            System.out.print(solution_decode(str2.charAt(i)));
        }
    }

    public static char solution_encode(char ch) {
        if (ch >= '0' && ch <= '8') {
            return (char) (ch + 1);
        } else if (ch == '9')
            return '0';
        if (ch >= 'A' && ch < 'Z') {
            return (char) (ch + 33);
        }
        if (ch == 'Z') {
            return 'a';
        }
        if (ch >= 'a' && ch < 'z') {
            return (char) (ch - 32 + 1);
        }
        if (ch == 'z') {
            return 'A';
        }
        return ch;
    }

    public static char solution_decode(char ch) {
        if (ch == '0') {
            return '9';
        }
        if (ch > '0' && ch <= '9') {
            return (char) (ch - 1);
        }
        if (ch == 'a') {
            return 'Z';
        }
        if (ch > 'a' && ch <= 'z') {
            return (char) (ch - 32 - 1);
        }
        if (ch == 'A') {
            return 'z';
        }
        if (ch > 'A' && ch <= 'Z') {
            return (char) (ch + 32 - 1);
        }
        return ch;
    }
}

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String str = "";
        while ((str = bf.readLine()) != null) {
            String str1 = Encrypt(str);
            System.out.println(str1);
            str = bf.readLine();
            String str2 = unEncrypt(str);
            System.out.println(str2);
        }
    }

    private static String Encrypt(String line) {
        char[] cha = line.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char c : cha) {
            if (c >= 'a' && c <= 'z') {
                if (c == 'z') {
                    sb.append('A');
                } else {
                    sb.append((char) (c + 1 - 32));
                }
            } else if (c >= 'A' && c <= 'Z') {
                if (c == 'Z') {
                    sb.append('a');
                } else {
                    sb.append((char) (c + 32 + 1));
                }
            } else if (c >= '0' && c <= '9') {
                if (c == '9') {
                    sb.append('0');
                } else {
                    sb.append(c - 48 + 1);
                    // sb.append((char)(cha[i]+1));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }


    private static String unEncrypt(String line) {
        char[] cha = line.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char c : cha) {
            if (c >= 'a' && c <= 'z') {
                if (c == 'a') {
                    sb.append('Z');
                } else {
                    sb.append((char) (c - 1 - 32));
                }
            } else if (c >= 'A' && c <= 'Z') {
                if (c == 'A') {
                    sb.append('z');
                } else {
                    sb.append((char) (c + 32 - 1));
                }
            } else if (c >= '0' && c <= '9') {
                if (c == '0') {
                    sb.append('9');
                } else {
                    sb.append(c - 48 - 1);
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}

牛客网-华为机试练习题 30
题目描述:字符串合并

按照指定规则对输入的字符串进行处理。

详细描述:

将输入的两个字符串合并。

对合并后的字符串进行排序,要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序。这里的下标意思是字符在字符串中的位置。

对排序后的字符串进行操作,如果字符为‘0’——‘9’或者‘A’——‘F’或者‘a’——‘f’,则对他们所代表的16进制的数进行BIT倒序的操作,并转换为相应的大写字符。如字符为‘4’,为0100b,则翻转后为0010b,也就是2。转换后的字符为‘2’; 如字符为‘7’,为0111b,则翻转后为1110b,也就是e。转换后的字符为大写‘E’。


举例:输入str1为"dec",str2为"fab",合并为“decfab”,分别对“dca”和“efb”进行排序,排序后为“abcedf”,转换后为“5D37BF”

接口设计及说明:

/*

功能:字符串处理

输入:两个字符串,需要异常处理

输出:合并处理后的字符串,具体要求参考文档

返回:无

*/

void ProcessString(char* str1,char *str2,char * strOutput)

{

}

输入描述:
输入两个字符串
输出描述:
输出转化后的结果

示例1

输入

dec fab

输出

5D37BF
解决代码
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            StringBuffer rs = new StringBuffer();
            char[] strmx = (sc.next() + sc.next()).toCharArray();
            String string1 = "";
            String string2 = "";
            for (int i = 0; i < strmx.length; i++) {
                if (i % 2 == 0) {
                    string1 += strmx[i];
                } else {
                    string2 += strmx[i];
                }
            }
            char[] str1 = string1.toCharArray();
            char[] str2 = string2.toCharArray();
            Arrays.sort(str1);
            Arrays.sort(str2);
            String strx = "";
            int k = 0;
            for (int i = 0; i < Math.min(str1.length, str2.length); i++) {
                strx += str1[i];
                strx += str2[i];
                if (i == Math.min(str1.length, str2.length) - 1) {
                    k = i;
                }
            }
            if (str1.length > str2.length) {
                strx += str1[k + 1];
            } else if (str1.length < str2.length) {
                strx += str2[k + 1];
            }
            char[] str = strx.toCharArray();
            for (char c : str) {
                if (String.valueOf(c).matches("[A-Fa-f]")) {
                    String res = revser(Integer.toBinaryString((int) Character.toLowerCase(c) - 87));
                    int x = Integer.parseInt(res, 2);
                    rs.append(Nx(x));
                } else if (String.valueOf(c).matches("[0-9]")) {
                    String res = "";
                    String hex = Integer.toBinaryString(Integer.parseInt(String.valueOf(c)));
                    if (hex.length() < 4) {
                        for (int j = 0; j < 4 - hex.length(); j++) {
                            res += "0";
                        }
                    }
                    String resx = revser(res + hex);
                    int x = Integer.parseInt(resx, 2);
                    rs.append(Nx(x));
                } else {
                    rs.append(c);
                }
            }
            System.out.println(rs);
        }
    }

    public static String revser(String srx) {
        StringBuffer sb = new StringBuffer();
        return sb.append(srx).reverse().toString();
    }

    public static String Nx(int x) {
        if (x == 10) {
            return "A";
        } else if (x == 11) {
            return "B";
        } else if (x == 12) {
            return "C";
        } else if (x == 13) {
            return "D";
        } else if (x == 14) {
            return "E";
        } else if (x == 15) {
            return "F";
        }
        return String.valueOf(x);
    }
}
牛客网-华为机试练习题 31
题目描述:单词倒排

对字符串中的所有单词进行倒排。

说明:

1、每个单词是以26个大写或小写英文字母构成;

2、非构成单词的字符均视为单词间隔符;

3、要求倒排后的单词间隔符以一个空格表示;如果原字符串中相邻单词间有多个间隔符时,倒排转换后也只允许出现一个空格间隔符;

4、每个单词最长20个字母;

输入描述:
输入一行以空格来分隔的句子
输出描述:
输出句子的逆序

示例1

输入

复制

I am a student

输出

复制

student a am I
解决代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line;
        while ((line = br.readLine()) != null) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < line.length(); i++) {
                char c = line.charAt(i);
                if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
                    sb.append(c);
                } else {
                    sb.append(' ');
                }
            }
            String[] str = sb.toString().trim().split(" ");
            StringBuffer s2 = new StringBuffer();
            for (int j = str.length - 1; j >= 0; j--) {
                if (!(str[j].equals(" "))) {
                    s2.append(str[j]);
                }
                if (j > 0) {
                    s2.append(" ");
                }
            }
            System.out.println(s2.toString());
        }
    }
}

牛客网-华为机试练习题 32
题目描述:字符串运用-密码截取

Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->
ABAKK,123321->51233214
。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗?

输入描述:
输入一个字符串
输出描述:
返回有效密码串的最大长度

示例1
输入
ABBA
输出
4
思路
  • 在每个字符的左右加上一个#,然后统计每个字符的最长回文半径

    ABBA
    #A#B#B#A#
    010141010
    
  • 最大的回文半径就是最终的结果

解决代码:
//同楼上一位答主一样,以每个字符(奇数长度的回文串)或者字符间空隙
//(偶数长度的回文串)分别向左向右扩充,记录遇到的最大长度

import java.util.Scanner;

public class Main {
    public static int process(String str) {
        int len = str.length();
        if (len < 1) {
            return 0;
        }
        int max = 1;//只要字符创长度大于1,则最短的回文串长度为1
        //考虑奇数个数的回文串
        for (int i = 1; i < len - 1; i++) {
            int k = i - 1, j = i + 1;
            int count = 0;
            while (k >= 0 && j <= len - 1) {
                if (str.charAt(k--) == str.charAt(j++)) {
                    count++;
                } else {
                    break;
                }
            }
            max = Math.max(max, (count * 2 + 1));
        }
        //现在考虑偶数回文串的情况,主要考虑字符之间的位置
        for (int i = 1; i < len - 1; i++) {
            int k = i - 1, j = i;
            int count = 0;
            while (k >= 0 && j <= len - 1) {
                if (str.charAt(k--) == str.charAt(j++)) {
                    count++;
                } else {
                    break;
                }
            }
            max = Math.max(max, count * 2);
        }
        return max;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            String str = in.next();
            System.out.println(process(str));
        }
        in.close();
    }
}


import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            String str = sc.nextLine();
            int num = Solution(str);
            System.out.println(num);
        }
    }

    public static int Solution(String str) {
        StringBuilder sbuf = new StringBuilder();
        sbuf.append('#');
        for (int i = 0; i < str.length(); i++) {
            sbuf.append(str.charAt(i));
            sbuf.append('#');
        }
        String new_str = sbuf.toString();
        char[] arr_str = new_str.toCharArray();
        int[] radius = new int[arr_str.length];
        radius[0] = 0;
        radius[radius.length - 1] = 0;
        for (int i = 1; i < arr_str.length - 1; i++) {
            int count = 1;
            while (i >= count && (i + count) < arr_str.length) {
                if (arr_str[i - count] == arr_str[i + count]) {
                    count++;
                } else {
                    break;
                }
            }
            radius[i] = count - 1;
        }
        int res = 0;
        for (int j : radius) {
            if (j > res)
                res = j;
        }
        return res;
    }
}
牛客网-华为机试练习题 33
题目描述:整数与IP地址间的转换
原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成
一个长整数。
举例:一个ip地址为10.0.3.193
每段数字             相对应的二进制数
10                   00001010
0                    00000000
3                    00000011
193                  11000001
组合起来即为:00001010 00000000 00000011 11000001,转换为10进制数就是:167773121,即该IP地址转换后的数字就是它了。

的每段可以看成是一个0-255的整数,需要对IP地址进行校验
输入描述:
输入 
1 输入IP地址
2 输入10进制型的IP地址
输出描述:
输出
1 输出转换成10进制的IP地址
2 输出转换后的IP地址

示例1

输入
10.0.3.193
167969729

输出
167773121
10.3.3.193
解决代码:
import java.util.*;
import java.io.*;

public class Main {
    public static void Change1(String str) {
        String[] data1 = str.split("\\.");
        data1[0] = Integer.toBinaryString(Integer.parseInt(data1[0]));
        data1[1] = Integer.toBinaryString(Integer.parseInt(data1[1]));
        data1[2] = Integer.toBinaryString(Integer.parseInt(data1[2]));
        data1[3] = Integer.toBinaryString(Integer.parseInt(data1[3]));
        while (data1[0].length() < 8) data1[0] = "0" + data1[0];
        while (data1[1].length() < 8) data1[1] = "0" + data1[1];
        while (data1[2].length() < 8) data1[2] = "0" + data1[2];
        while (data1[3].length() < 8) data1[3] = "0" + data1[3];
        long sum = 0;
        for (String s : data1) {
            for (int j = 0; j < data1[0].length(); j++) {
                sum = sum * 2 + (s.charAt(j) - '0');
            }
        }
        System.out.println(sum);
    }

    public static void Change2(String str) {
        long data2 = Long.parseLong(str);
        String bindata2 = Long.toBinaryString(data2);
        String[] data = new String[4];
        data[0] = bindata2.substring(0, bindata2.length() - 3 * 8);
        data[1] = bindata2.substring(data[0].length(), data[0].length() + 8);
        data[2] = bindata2.substring(data[0].length() + data[1].length(), data[0].length() + data[1].length() + 8);
        data[3] = bindata2.substring(bindata2.length() - 8);
        System.out.print(Integer.valueOf(data[0], 2) + ".");
        System.out.print(Integer.valueOf(data[1], 2) + ".");
        System.out.print(Integer.valueOf(data[2], 2) + ".");
        System.out.println(Integer.valueOf(data[3], 2));
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;
        while ((str = br.readLine()) != null) {
            Change1(str);
            str = br.readLine();
            Change2(str);
        }
    }
}
总结
  • public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new
    InputStreamReader(System.in));

需要加throws IOException

  • Long.toBinaryString可以将数字处理成二进制字符串
  • Integer.valueOf可以获得字符串对应的数字。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值