牛客刷题笔记-华为机试(一)

1、HJ15 输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        String b = Integer.toBinaryString(n);
        int count = 0;
        for(int i=0;i<b.length();i++){
            if(b.charAt(i)=='1') {
            	count++;
            }
        }
        System.out.println(count);
    }
}

我的方法比较基础,学习一下别人有趣的方法。位运算:

import java.util.*;
 public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int count = 0;
        for (int i = 1; i <= 32; i++) {
            count += n & 1;
            n >>= 1;
        }
        System.out.println(count);
    }
}

Java提供的位运算符有:左移( << )、右移( >> ) 、无符号右移( >>> ) 、位与( & ) 、位或( | )、位非( ~ )、位异或( ^ ),除了位非( ~ )是一元操作符外,其它的都是二元操作符。
参考

2、HJ50 输入一个表达式(用字符串表示),求这个表达式的值。保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。

这道题我想到了用两个栈来解决,但是没想明白具体方法,直接来看参考题解。

import java.util.*;
public class Main{
    // 用于存放一个正括号的集合, 用于简化代码
    static Set<Character> brace = new HashSet<>();
    public static void main(String ... args){
        Scanner sc = new Scanner(System.in);
        // 初始化正括号集合
        brace.add('{');
        brace.add('(');
        brace.add('[');
        while(sc.hasNextLine()){
            // 对字符串做初始化处理,原则有二:
            // 1、处理负数,这里在-前面的位置加入一个0,如-4变为0-4,
            // 细节:注意-开头的地方前面一定不能是数字或者反括号,如9-0,(3-4)-5,这里地方是不能加0的
            // 它的后面可以是数字或者正括号,如-9=>0-9, -(3*3)=>0-(3*3)
            // 2、处理字符串,在最后的位置加#, 主要是为了防止最后一个整数无法处理的问题
            String exp = sc.nextLine().replaceAll("(?<![0-9)}\\]])(?=-[0-9({\\[])", "0") + "#";
            System.out.println(calculate(exp));
        }
    }
    private static int calculate(String exp){
        // 初始化栈
        Stack<Integer> opStack = new Stack<>();
        Stack<Character> otStack = new Stack<>();
        
        // 整数记录器
        String num = "";
        for(int i = 0; i < exp.length(); i++){
            // 抽取字符
            char c = exp.charAt(i);
            // 如果字符是数字,则加这个数字累加到num后面
            if(Character.isDigit(c)){
                num += c;
            }
            // 如果不是数字
            else{
                // 如果有字符串被记录,则操作数入栈,并清空
                if(!num.isEmpty()){
                    int n = Integer.parseInt(num);
                    num = "";
                    opStack.push(n);
                }
                // 如果遇上了终结符则退出
                if(c == '#')
                    break;
                // 如果遇上了+-
                else if(c == '+' || c == '-'){
                    // 空栈或者操作符栈顶遇到正括号,则入栈
                    if(otStack.isEmpty() || brace.contains(otStack.peek())){
                        otStack.push(c);
                    } else {
                        // 否则一直做弹栈计算,直到空或者遇到正括号为止,最后入栈
                        while(!otStack.isEmpty() && !brace.contains(otStack.peek()))
                            popAndCal(opStack, otStack);
                        otStack.push(c);
                    }
                }
                // 如果遇上*/
                else if(c == '*' || c == '/'){
                    // 空栈或者遇到操作符栈顶是括号,或者遇到优先级低的运算符,则入栈
                    if(otStack.isEmpty()
                            || brace.contains(otStack.peek())
                            || otStack.peek() == '+' || otStack.peek() == '-'){
                        otStack.push(c);
                    }else{
                        // 否则遇到*或/则一直做弹栈计算,直到栈顶是优先级比自己低的符号,最后入栈
                        while(!otStack.isEmpty()
                                && otStack.peek() != '+' && otStack.peek() != '-'
                                && !brace.contains(otStack.peek()))
                            popAndCal(opStack, otStack);
                        otStack.push(c);
                    }
                } else {
                    // 如果是正括号就压栈
                    if(brace.contains(c))
                        otStack.push(c);
                    else{
                        // 反括号就一直做弹栈计算,直到遇到正括号为止
                        char r = getBrace(c);
                        while(otStack.peek() != r){
                            popAndCal(opStack, otStack);
                        }
                        // 最后弹出正括号
                        otStack.pop();
                    }
                }
            }
        }
        // 将剩下的计算完,直到运算符栈为空
        while(!otStack.isEmpty())
            popAndCal(opStack, otStack);
        // 返回结果
        return opStack.pop();
    }
    private static void popAndCal(Stack<Integer> opStack, Stack<Character> otStack){
        int op2 = opStack.pop();
        int op1 = opStack.pop();
        char ot = otStack.pop();
        int res = 0;
        switch(ot){
            case '+':
                res = op1 + op2;
                break;
            case '-':
                res = op1 - op2;
                break;
            case '*':
                res = op1 * op2;
                break;
            case '/':
                res = op1 / op2;
                break;
        }
        opStack.push(res);
    }
    private static char getBrace(char brace){
        switch(brace){
            case ')':
                return '(';
            case ']':
                return '[';
            case '}':
                return '{';
        }
        return '#';
    }
}
3、HJ108 正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。
import java.util.*;
public class Main{
    public static int common(int a, int b){
        if (b == 0) return a;
        return a % b == 0 ? b : common(b, a%b);
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int com = common(a,b);
        System.out.println(a*b/com);
        sc.close();
    }
}

思路:先求最大公约。忘了最大公约怎么求了(辗转相除),看了下题解发现了这个递归用法挺巧的。

4、HJ84 找出给定字符串中大写字符(即’A’-‘Z’)的个数。
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            String str = sc.nextLine();
            int count = 0;
            for(int i=0;i<str.length();i++){
                char c = str.charAt(i);
                if(c>=65&&c<=90){
                    count++;
                }
            }
            System.out.println(count);
        }
        sc.close();
    }
}

常规思路做完,照例看一下骚操作。

import java.util.*;
public class Main{
    public static void main(String[] arg){
        Scanner s=new Scanner(System.in);
        while(s.hasNextLine()){
            String input1=s.nextLine();
            String input=input1.replaceAll("([A-Z]+)","");
            System.out.println(input1.length()-input.length());
        }
    }
}

用String.replaceAll("([A-Z]+)",""),把字符串中的大写字母消除,然后相减得出个数、

5、HJ61 把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。数据范围:0<=m<=10,1<=n<=10。本题含有多组样例输入。
import java.util.*;
public class Main{
    public static int setApple(int m,int n){
        if(m<0||n<=0){
            return 0;
        }
        if(m==1||n==1||m==0){
            return 1;
        }
        return setApple(m,n-1)+setApple(m-n,n);
    }
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNextInt())
        {
            int m = sc.nextInt();
            int n = sc.nextInt();
            System.out.println(setApple(m,n));
        }
        sc.close();
    }
}

每个事件可以分为f(m,n)=f(m-n,n)+f(m,n-1);f(m-n,n)是当苹果数大于等于盘子数的情况,f(m,n-1)是当苹果数小于盘子数的情况。当此事件分到苹果数为0或苹果数为1或盘子数为1的时候返回1,当苹果数小于0或盘子数小于等于0返回0。

6、HJ2 写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字母,然后输出输入字符串中该字母的出现次数。不区分大小写。
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine().toLowerCase();
        char c = sc.nextLine().toLowerCase().charAt(0);
        System.out.println(nums(str,c));
    }

    public static int nums(String str,char c){
        int i = 0;
        char[] chars = str.toCharArray();
        for(char ch:chars){
            if(c == ch ){
                i++;
            }
        }
        return i;
    }
}

我是用65-90,,97-122写的判断,这里学习了新方法:toLowerCase(),将字符串中的大写字母都转换成小写字母(同理也可用toUpperCase())。或者还可以用上面的String.replaceAll做减法。

import java.util.*;
public class Main{
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		String str =sc.nextLine().toLowerCase();
		String s = sc.nextLine().toLowerCase();
		System.out.print(str.length()-str.replaceAll(s,"").length());
		sc.close();
		}
}
7、HJ10 编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次,例如,对于字符串abaca而言,有a、b、c三种不同的字符,因此输出3。
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        char[] c = sc.nextLine().toCharArray();
        HashSet hs = new HashSet();
        for(int i=0;i<c.length;i++){
            if(c[i]>=0&&c[i]<=127){
                hs.add(c[i]);
            }
        }
        System.out.println(hs.size());
        sc.close();
    }
}

由于不统计重复字符,因此想到了set集合。set.size()获取集合中元素个数。

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

我的代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        int l = s.length();
        HashMap<Integer,Integer> map = new HashMap<>();
        map.put(1,s.charAt(l-1)-48);
        for(int i=2;i<=l;i++){
            if(!map.containsValue(s.charAt(l-i)-48)){
                map.put(i,s.charAt(l-i)-48);
            }
            else map.put(i,null);
        }
        for(int i=1;i<=map.size();i++){
            if(map.get(i)!=null){
                System.out.print(map.get(i));
            }
        }
    }
} 

参考一下用Set的简单方法(之前考虑set了,但是set是无序的,万万没想到还可以直接输出)

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        Set<Character> set = new HashSet<>();
        for(int i = s.length() - 1; i >= 0; i--) {
            if(set.add(s.charAt(i))) {
                System.out.print(s.charAt(i));
            }
        }
    }
}
9、HJ8 数据表记录包含表索引和数值(int范围的正整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。

我的代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = Integer.parseInt(sc.nextLine());
        TreeMap<Integer,Integer> tree = new TreeMap<>();
        for(int i=0;i<n;i++){
            String str = sc.nextLine();
            String[] s = str.split(" ");
            int index = Integer.parseInt(s[0]);
            int value = Integer.parseInt(s[1]);
            if(tree.containsKey(index)){
                tree.replace(index,tree.get(index),tree.get(index)+value);
            }
            else{
                tree.put(index,value);
            }
        }
        for(int j:tree.keySet()){
            System.out.println(j+" "+tree.get(j));
        }
        sc.close();
    }
}

新学到的知识点,HashMap/HashSet都是无序的,即插入元素后直接按照Key自动排列,想要插入有序可以用TreeMapArrayList也是有序的,但是只包含值不包含键值对,LinkList也是有序的,常用于频繁访问的情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值