华为机试题目菜鸟笔记C++&Java
华为机试菜鸟笔记C++&Java
1. 字符串最后一个单词的长度
#include<bits/stdc++.h>//万能头文件
using namespace std;
int main(){
string s;
while(cin >> s);
cout << s.size();
return 0;
}
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
- cin输入的机制,有空格会停止,系统把空格作为数据间的分隔符,整个英文句子会一个单词一个单词的读。非常巧妙的使用了cin的读取逻辑。
- cin.getline()接收字符串,可以输入空格并输出。
- https://baike.baidu.com/item/cin/23384763?fr=aladdin
2.计算某字符出现次数
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
getline(cin, s);//输入字符串
char c = tolower(getchar());//字符小写
uint16_t n = 0;
for (auto i : s) { //简单理解为 从第一个字符遍历
if (tolower(i) == c) {
++n;
}
}
cout << n << endl;
}
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
- tolower()是一种函数,功能是把字母字符转换成小写,非字母字符不做出处理。
- getchar()函数的作用是从计算机终端(一般为键盘)获取一个无符号字符。
typedefint int16_t; typedef unsigned int uint16_t;
- uint16_t 这些数据类型中都带有_t, _t 表示这些数据类型是通过typedef定义的,而不是新的数据类型。也就是说,它们其实是我们已知的类型的别名。使用的原因:方便代码的维护。
- https://blog.csdn.net/xiejingfa/article/details/50469045
3.HJ3 明明的随机数
#include<bits/stdc++.h>
int main(){
int n;
int a;
//以数组下标来存储随机数,下标对应的数组值为1,来说明是否是存储的随机数
while(~scanf("%d",&n)){//while(~scanf("%d",&n))<=> while(scanf("%d",&n)!=EOF)
int count[1001]={0};
int i;
for(i=0;i<n;i++){
scanf("%d",&a);//&:引用或者指针、
count[a]=1;
}
for(i=0;i<1001;i++){
if(count[i]==1){
printf("%d\n",i);
}
}
}
return 0;
}
}
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
while(~scanf("%d",&n)) <=> while(scanf("%d",&n)!=EOF)
-1在内存中:1111 1111(八个一),原理如下:设(1111 1111)为原码,如果要想知道原码的十进制数是多少,需要做一下处理。
先判断:当最高位是0时,表示正数,正数的原码=反码=补码,当最高位为1时,表示负数,负数的原码取反为反码,然后反码加一为补码,补码就是这个负数的绝对值。
,第一步,取反;最高位为符号位,把(1111 1111)取反就为反码(0000 0000)8个0,
第二步,反码加一;加1等于(0000 0001),这儿等到的(0000 0001)就是(1111 1111)的补码,补码(0000 0001)的十进制是1,这儿的1就是这个负数的绝对值。完毕。
4.HJ4 字符串分隔.
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str;
while (cin >> str)
{
// 补0
int len = str.size();
if (len % 8 != 0)
{
int count = 8 - len % 8;
str.append(count, '0');//添加几个相同的字符:
}
// 按格式输出
int newLen = str.size();
for (int i = 0; i < newLen; i += 8)
{
cout << str.substr(i, 8) << endl;//从i开始输出8个长度的字符串
}
}
return 0;
}
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
value = atoi(dateStr.substr(i, 2).c_str());
里面包含三个函数,分别是atoi(),substr(),c_str().
百度:
atoi()函数原型为: int atoi(char *str),用途是将字符串转换成一个整数值,str是待转化成整数值的字符串.成功则返回转化后的整数值,失败返回0.
substr()函数原型为:basic string::substr(string,start,length),也可把string移到外面,为string &a,a.substr(start,length),其中a是待截取的字符串,start表示从截取开始的前一位,length表示截取长度,例如string &a="hello world",则a.substr(6,5)=world.
c_str()函数原型为:const char c_str(),如果要将string对象,转化为char对象,c_str()提供了这样一种方法,它返回一个客户程序可读不可改的指向字符数组的指针。
所以value=atoi(dateStr.substr(i,2).c_str())的作用就是,截取string型的对象dateStr,从第i个字符截取2个长度的,并转化为char*对象,然后将此字符串转换成一个整数值,赋值给value(value是int型).
5.HJ5 进制转换
#include<bits/stdc++.h>
using namespace std;
int main() {
string str;
while (cin >> str) {
cout << stoi(str, 0, 16) << endl;
}
}
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
stoi()表示将字符串转换为整数 ,它是C ++ STL中的标准库函数,用于将各种格式(例如二进制,八进制,十六进制或字符串格式的简单数字)的给定字符串转换为整数。
句法:int stoi(字符串,起始位置,n进制),将 n 进制的字符串转化为十进制
6.HJ6 质数因子
质数/素数:质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)。
质数因子:质因子(或质因数)在数论里是指能整除给定正整数的质数。根据算术基本定理,不考虑排列顺序下,每个正整数都能够以唯一的方式表示成它的质因数的乘积。下面求解某一个数的质因子的情况。
C ++中的sqrt(x)函数返回数字的平方根。x为int、double、float类型的非负参数
双单引号区别:"字符串"、'单字符'
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
//创建扫描器对象
Scanner scanner = new Scanner(System.in);
//从键盘中接收输入
long num = scanner.nextLong();
//我们判断数 num 是不是质数时,没必要从 2 一直尝试到 num 此题中的大循环也大可不必写一个到 num 的循环,写到num的平方根即可,如果此时数字还没有除数,则可判定其本身是一个质数,没有再除下去的必要了,直接打印其本身即可
long k = (long)Math.sqrt(num);
//先求num的质数,
//注意,num一直在变小,这就暗含了一个现象或者说理论吧,就是从小到大试:如果一个数已经不能整除2了,那么这个数肯定不能整除2的倍数;同理3也一样,所以整个循环能够保证一旦出现新的因数,其一定就是质数
for (long i = 2; i <= k ; ++i) {
while (num % i == 0) {
System.out.print(i + " ");
num /= i;
}
}
System.out.println(num==1?"":num+"");
}
}
- next():next()方法将输入读取到空格字符。一旦遇到空格,它就返回字符串(不包括空格)。
- nextLine():与next()不同,nextLine()方法读取包括空格在内的整个输入行。当该方法遇到下一行字符\n时终止。
7.HJ7 取近似值
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
double number = in.nextDouble();
System.out.println((int)(number + 0.5));
}
}
8.HJ8 合并表记录
知识点1:
Java Map接口
Java HashMap
Java for-each循环(遍历循环/增强的for循环)
知识点2:
Java 基本数据类型及取值范围
解惑:
main主函数(主方法)里头的参数String[] args有啥作用?
int 和 Integer 的区别
int 和 Integer的区别主要体现在以下几个方面:
- 数据类型不同:int是基础数据类型,而 Integer是包装数据类型;
- 默认值不同:int的默认值是 0,而 Integer的默认值是 null;
- 内存中存储的方式不同:int 在内存中直接存储的是数据值,而 Integer实际存储的是对象引用,当 new 一个 Integer 时实际上是生成一个指针指向此对象;
- 实例化方式不同:Integer 必须实例化才可以使用,而 int 不需要;包装类的存在解决了基本数据类型无法做到的事情泛型类型参数、序列化、类型转换、高频区间数据缓存等问题。
- 变量的比较方式不同:int 可以使用 == 来对比两个变量是否相等,而 Integer一定要使用 equals 来比较两个变量是否相等。
采用hash表存放数据就好了,每次输入查询是否有存在的key,存在就将value累加到表中,最后输出表。
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int tableSize = scanner.nextInt();
//使用HashMap类创建map,tablesize为table容量
Map<Integer, Integer> table = new HashMap<>(tableSize);
for (int i = 0; i < tableSize; i++) {
int key = scanner.nextInt();
int value = scanner.nextInt();
//containsKey(key)检查指定的键Key是否在map中
if (table.containsKey(key)) {
table.put(key, table.get(key) + value);
} else {
table.put(key, value);
}
}
//for-each循环增强的for循环,更易写和可读
for (Integer key : table.keySet()) {//返回Map集合中存在的所有键的集合
System.out.println( key + " " + table.get(key));
}
}
}
9.HJ9 提取不重复的整数
大知识点:java集合框架之间的关系和对应联系。
知识点:
/ 在java中表示整除,整数和整数运算得到的一定是整数;只要有小数参与整除/得到的一定是小数。
有时间看:
区分点:
集合框架与Collection(集合)接口:Collection接口是集合框架的根接口。 该框架还包括其他接口:Map和Iterator。 这些接口也可能具有子接口。
&---Collection接口:单列集合,用来存储一个一个的对象 &---List接口:存储有序的、可重复的数据。 -->“动态”数组 (ArrayList、LinkedList、Vector) &---Set接口:存储无序的、不可重复的数据 -->高中讲的“集合” (HashSet、LinkedHashSet、TreeSet) &---Queue接口:先进先出的方式存储与访问 &---Map接口:双列集合,用来存储一对(key - value)一对的数据 -->高中函数:y = f(x) (HashMap、LinkedHashMap、TreeMap、Hashtable、Properties) Java Iterator 接口 在Java中,Iterator接口提供了用于访问集合元素的方法。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (sc.hasNext()) {
// 使用HashSet来判断是否是不重复的
//当执行add添加后会返回一个 boolean,如过插入成功则放回true反正则为false
HashSet<Integer> hs = new HashSet<>();//默认容量将为 16,负载因子将为 0.75
int target = sc.nextInt();//Scanner的方法
while (target != 0) {
int temp=target%10;
if(hs.add(temp))
System.out.print(temp);
// 除10能去掉最右边的数字,/ 在java中表示整除,整数和整数运算得到的一定是整数;只要有小数参与整除/得到的一定是小数。
target/=10;
}
System.out.println();
}
}
}
知识点:
[StringBuffur]:见11题
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//逆序排列,StringBuilder(String str),并调用StringBuilder的reverse()将字符串翻转。
StringBuilder stringBuilder = new StringBuilder(scanner.nextLine()).reverse();
String str = stringBuilder.toString();//j转换为String对象。
//结果集
StringBuilder result = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
//indexOf() 返回字符串中指定字符/子字符串首次出现的索引。
//charAt() 返回给定索引处的字符
if (str.indexOf(str.charAt(i)) == i) {
//append(obj)添加任意类的字符串,并返回当前对象(StringBuilder)
result.append(str.charAt(i));
}
}
System.out.println(result.toString());
}
}
10.HJ10 字符个数统计
知识点:
Java BitSet类:Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。
BitSet就是位图,它的值只有1和0。内部是基于long[]实现的,long是8字节(64位),所以Bitset最小是64位,每次扩大一次扩大64位,即内部大小是64的倍数。每次BitSet新增加一个数字时,就将该位置为1。也就是说BitSet并不直接存储每个数据,而是存储数字是否存在过(1表示存在,0表示不存在)。
字节(byte)、位/比特(bite)、字符之间的关系。
**
bit比特/位**:二进制的每一个0/1 位,计算机内部数据储存的最小单位。**
byte字节**:字节是计算机中最小的存储单元
计算机中 数据处理 的基本单位,任何数据都是以字节的方式存储。
一个byte(字节) = 8个bit(位)即0000-0000,8个二进制位。**
char字符 :占用2个byte(字节)**Java--位、字节、字符、字符编码、数据存储单位 & 电脑的32位和64位的区别是什么呢
大小关系:bit(位/比特) < byte(字节) < kb(千字节) < MB(兆字节) < GB(吉字节) < TB(太字节) <.....
A?B:C 其实为Java中的三元运算符,表示条件判断语句,对布尔类型的语句进行判断,即 A ? B : C,表示:如果语句A为真,则执行语句B,如果语句A为假,则执行语句C。
凡是涉及到去重统计都可以用位图实现。因为每一个不同的数据只需要用二进制的一位存储即可,大大减小了统计所使用的存储空间
import java.util.Scanner;
import java.util.BitSet;
public class Main {
public static void main(String[] args) {
Scanner scannner = new Scanner(System.in);
String str=scannner.next();
//总共有128个字符。字需要用128位
BitSet bitSet=new BitSet(128);//BitSet位图
for(char c:str.toCharArray()){//toCharArray():将字符串转换为char数组
//判断字符c是否已出现
if(!bitSet.get(c)){/*boolean get(int index)
返回指定索引处的位值。自动类型转换。。。而且转成的int恰好就是该字符对应的ASCII码*/
//未出现就设置为已出现
bitSet.set(c);//void set(int index):将指定索引处的位设置为 true。
}
}
//统计有多少字符出现过
System.out.println(bitSet.cardinality());//int cardinality( ):返回此 BitSet 中设置为 true 的位数。
}
}
11.HJ11 数字颠倒
知识点:
StringBuilder 和 StringBuffer 是一对兄弟,因为它们拥有同一个父类 AbstractStringBuilder,同时实现的接口也是完全一样,都实现了 java.io.Serializable, CharSequence 两个接口。
那它们有什么区别呢?最大的区别在于 StringBuffer 对几乎所有的方法都实现了同步,StringBuilder 没有实现同步,如同样是对 AbstractStringBuilder 方法 append 的重写,StringBuffer 添加了 synchronized 关键字修饰,而 StringBuilder 没有。
所以 StringBuffer 是线程安全的,在多线程系统中可以保证数据同步,而 StringBuilder 无法保证线程安全,所以多线程系统中不能使用 StringBuilder。
但是方法同步需要消耗一定的系统资源,所以 StringBuffer 虽然安全,但是效率不如 StringBuilder,也就是说使用 StringBuilder 更快。
String、StringBuffer、StringBuilder 有什么区别?
1、String 一旦创建不可变,如果修改即创建新的对象,StringBuffer 和 StringBuilder 可变,修改之后引用不变。
2、String 对象直接拼接效率高,但是如果执行的是间接拼接,效率很低,而 StringBuffer 和 StringBuilder 的效率更高,同时 StringBuilder 的效率高于 StringBuffer。
3、StringBuffer 的方法是线程安全的,StringBuilder 是线程不安全的,在考虑线程安全的情况下,应该使用 StringBuffer。
next() 和 nextLine()的区别``(可以输入数值型数据,返回值为String)
-
String next() :next()方法不能得到带有空格的字符串。一旦遇到空格,它就返回字符串(不包括空格)。-
String nextLine():与next()不同,nextLine()方法读取包括空格在内的整个输入行。当该方法遇到下一行字符\n时终止。hasNext() 和 hasNextLine() 的区别``(返回值为Boolean)
-
boolean hasNext():断接下来是否有非空字符.如果有,则返回true。-
boolean hasNextLine():根据行匹配模式去判断接下来是否有一行(包括空行),如果有,则返回true。总结:采用hasNextXxxx() 的话,后面也要用nextXxxx()
如果要输入 int 或 float 类型的数据,在 Scanner 类中也有支持,但是在输入之前最好先使用 hasNextXxx() 方法进行验证,再使用 nextXxx() 来读取:
采用hasNextXxxx() 的话,后面也要用nextXxxx(): 比如前面用hasNextLine(),那么后面要用 nextLine() 来处理输入; 后面用 nextInt() 方法的话,那么前面要使用 hasNext()方法去判断.
附上java如何在输入空时让scanner类自动结束
public static void main(String[] args){ Scanner sc = new Scanner(System.in); while (sc.hasNextLine()){ String str = sc.nextLine(); if(str.isEmpty()){ break; } System.out.println(str); } }
菜鸟随记:
- 使用一下java中的注释标签
/**
* @author PickUpShells
* @version 1.0.0
* @ClassName HW11.java
* @Description 数字颠倒
* @createTime 2022年01月19日 11:51:00
*/
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
String str =in.nextLine();//可以输入int类型,会被转换为字符串,以/n(回车)未结束符
StringBuffer strb=new StringBuffer(str);//StringBuffer比StringBuilder略慢但是线程安全
strb.reverse();//字符串顺序翻转
System.out.println(strb.toString());
}
}
12.HJ12 字符串反转
知识点:
System.out.print和System.out.println区别
参数有区别:
System.out.println() 可以不写参数
System.out.print(参数) 参数不能为空.必须有
效果有区别
println :会在输出完信息后进行换行,产生一个新行
print: 不会产生新行
println更简洁, print更灵活
print可以后面跟"\n"来达到和println一样的效果也可以跟"\t" 制表符, 等.
对象定义中的<>
相关:java泛型
Stack<Type> stacks = new Stack<>(); //<Type>数据类型,代表该Stack中只能放入Type类或者其子类的实例。 //? 第二个<>也许指的是大小
菜鸟随记:改版了,更换为有序列表
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Stack stack=new Stack();
String str=in.nextLine();
for(int i=0; i< str.trim().length();i++){//trim():删除任何前导(开始)和尾随(结束)空格,这里没有也可以
stack.push(str.charAt(i));///push():将元素添加到堆栈的顶部
}
while(!stack.empty()){//empty():检查堆栈是否为空
System.out.print(stack.pop());//pop():从堆栈顶部删除元素,并返回该元素
}
}
}
13.HJ13 句子逆序
知识点:
Java String split()方法在指定的正则表达式处分割字符串,并返回子字符串数组。
string.split(String regex, int limit)
- regex - 字符串在此正则表达式处分割(可以是字符串)
- limit (可选)-指定生成的子字符串的数量
如果未传递参数limit,则split()返回所有可能的子字符串。
菜鸟随记:初次接触正则表达式,之前也听说,见过但是他认识我我不认识他了。ε=(´ο`*)))唉
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String str=in.nextLine();
String s[]=str.split(" ");//split():将字符串拆分为指定的字符串(正则表达式)
for(int i=s.length-1;i>=0;i--){
if(i!=0)
System.out.print(s[i]+" ");
else
System.out.print(s[i]);
}
}
}
14.HJ14 字符串排序
知识点:
- IOException :IOException也称为检查异常。它们由编译器在编译时检查,并提示程序员处理这些异常。
- RuntimeException:一个运行时异常发生由于编程错误。它们也称为非检查异常。这些异常不在编译时检查,而是在运行时检查。
一个流被定义为一个数据序列。输入流用于从源读取数据,输出流用于向目标写数据。下图是一个描述输入流和输出流的类层次图。
BufferedReader InputStreamReader
- br.readLine():read() 方法从控制台读取一个字符,或者用 readLine() 方法读取一个字符串。
- br.close():关闭缓冲的读取器,调用close()方法后,我们将无法使用读取器读取数据。
InputStreamReader.ready()
通知此流是否已准备好被读取。
如果下一读取保证不会阻塞输入,该方法返回true,否则返回false。
将字符串参数作为有符号的十进制整数进行解析。
如果方法有两个参数, 使用第二个参数指定的基数(进制数),将字符串参数解析为有符号的整数。
.forEach(System.out::println);
Java Lambda 表达式//? 没看
Java8 推出了属于Java的lambda表达式,与一众的 => 不同,Java选择了 -> 做为箭头符号。
ambda表达式的基本格式:()->{}
Arrays.stream(ss).sorted().forEach(System.out::println);
list.forEach(System.out::println);
.forEach()
函数式接口
::是什么,怎么使用
pq.offer(s);
菜鸟随记:这个解法完全超出我知识范围了,呜呜呜。知识点太多了,看了一遍好像啥也没记住o(╥﹏╥)o,尤其是这个lambda表达式和.forEach()
import java.util.*;
import java.io.*;
public class Main {
// API中的sort方法大多使用快排或者归并排序;
// stream可以更方便写代码,但在不同数据量但情况下效率不同,姑且可以认为更耗时
//主函数调用实现方法解决问题
public static void main(String[] args) throws IOException {
withArraysAPI();
//withComparator();
//withPriorityQueue();
}
//方法1:调用API实现
public static void withArraysAPI() throws IOException {
//从输入流中读取并存储数组中的字符串
//读取控制台输入:Java 的控制台输入由 System.in 完成。为了获得一个绑定到控制台的字符流,你可以把 System.in 包装在一个 BufferedReader 对象中来创建一个字符流。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//Integer.parseInt br.readLine()
int n = Integer.parseInt(br.readLine());
String[] ss = new String[n]; //?n
for (int i = 0; i < n; ++i) {
ss[i] = br.readLine();
}
br.close();
// use stream to sort and output strings, which may use more time
Arrays.stream(ss).sorted().forEach(System.out::println);
// 或许, 使用 Arrays.sort(Object[] a) and for loop to output, which may use less time
}
//方法二: 使用PriorityQueue
public static void withPriorityQueue()throws IOException {
// read and store strings in a priority queue from input stream
PriorityQueue<String> pq = new PriorityQueue<>();
//BufferedReader InputStreamReader(System.in)
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();//ReadLine:read the first line, but the number will not be used.
String s;
while ((s = br.readLine()) != null) {
pq.offer(s);//pq.offer(s)
}
br.close();
//输出
while (!pq.isEmpty()) {
System.out.println(pq.poll());//pq.poll()
}
}
//方法三: 使用list并自己实现Comparator
public static void withComparator() throws IOException {
// read and store strings in a list from input stream
List <String> list = new ArrayList<>();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();// 读取第一行,但将不使用该数字。
String s;
while ((s = br.readLine()) != null) {
list.add(s);
}
br.close();
//sort with self defined comparator
list.sort((s1, s2) -> {
int i = 0;
while (i < s1.length() && i < s2.length()) {
if (s1.charAt(i) > s2.charAt(i)) {
return 1;
} else if (s1.charAt(i) < s2.charAt(i)) {
return -1;
} else {
i++;
}
}
return s1.length() - s2.length();
});
// indeed, default comparator works for this case
// list.sort(null);
// or you may use Collections.sort method to avoid null
// Collections.sort(list);
//输出
list.forEach(System.out::println);//?::
}
}
15.HJ15 求int型正整数在内存中存储时1的个数
知识点:
num&1:num与1做按位与,可以判断num的奇偶性。
按位与结果取决于num最后一位,如果num最后一位是1,则结果为1,反之结果为0。
if( (n&1)==1 ) 判断num最后1位是否为1,可以用来判断奇偶性。
举例:num=3的话
3与1的与运算就是(先写成2进制,然后同位比较,都为1时此位为1,否则为0):
11 & 01 = 01
因此 3与1的与运算就是1拓展:位运算——按位与(&)、按位或(|)、按位异或(^)
按位与(&)
两个数进行按位与运算时,先将其分别换算成二进制数再进行运算,按位与简单的理解就是同位上的两个数只有同为真时则真,一假则假,1为真,0为假
示例:17&23结果为十进制就是17
0000 0000 0001 0001(17)
0000 0000 0001 0111(23)
——————————
0000 0000 0001 0001(17)按位或(|)
同上方式,只是要求是一真为真,同假才假,只要有一个为1则为1,只有都是0的时候才为0,同样用刚才的例子17与23进行按位或运算
示例:17|23=23
0000 0000 0001 0001(17)
0000 0000 0001 0111(23)
——————————
0000 0000 0001 0111(23)取反(~)
每个位上都取相反值,1变成0,0变成1。
0000 0000 0001 0001(17)
1111 1111 1110 1110(~17)
所以:~17 =1111 1111 1110 1110
按位异或(^)
同为假,异为真,还是17和23
0000 0000 0001 0001
0000 0000 0001 0111
——————————
0000 0000 0000 0110
所以:17^23=0000 0000 0000 0110
总结:任何数与0异或,结果都是其本身。利用异或可以实现交换算法,例:左移(<<)
将一个数各二进制位全部向左移动若干位。
示例:17<< 2 =0000 0000 0100 0100 =68
左移一位的结果就是原值乘2,左移两位的结果就是原值乘4。
右移(>>)
将一个数各二进制位全部向右移动若干位。
示例:17 >> 2 =0000 0000 0000 0100 = 4
右移一位的结果就是原值除2,右移两位的结果就是原值除4,除了以后没有小数位的,都是取整。
菜鸟随记:
比较简单,缓解一下我焦虑的心情:真不错啊、真不错...
先把十进制数字转成二进制数字的字符串,再将字符串中的“0”全部替换为空,字符串的长度就是1的个数。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int num = in.nextInt();
String str = Integer.toBinaryString(num);
String newStr = str.replaceAll("0", "");
System.out.println(newStr.length());
}
}
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int num = in.nextInt(); //读取数字
int n = 0; //计数变量
for(int i=0; i < 32; i++){
if((num&1) == 1) //如果末位为1则计数
n++;
num = num >>> 1; //无符号右移
}
System.out.println(n);
}
}
知识点:
-
菜鸟随记:
知识点:
-
菜鸟随记:
16.HJ16 购物单
知识点:
0\1背包问题:听懂不翻车系列之--背包问//? 待完成
第一节课:0/1背包问题
基本型:归纳得出,存储了所有的决策结果
完全型:由上推下,滚动数组1行(空间压缩:优化空间复杂度)
第二节课:
菜鸟随记:遇到的第一个难题,之前都不算难,呜呜呜。
本题为变形的01背包:题目提示
物品数组:
物品\属性 0是价格 1是重要度 2是主附件 3是附件1 4是附件2…… i物品编号…… 背包数组:money+1是元素个数==数组下标money
j剩余的钱 价值*重要度money+1 …… …… 0 几种选择情况
一. 只买主件
二. 买主件和第一个附件
三. 买主件和第二个附件
四. 买主件和两个附件
五. 什么都不买
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int money = sc.nextInt();//有多少钱
int num = sc.nextInt();//物品个数
//0是价格,1是重要度,2是主附件,3是附件1,4是附件2.
int[][] goods = new int[num + 1][5];
for (int i = 1; i <= num; i++) {
int v = sc.nextInt();
int p = sc.nextInt();
int q = sc.nextInt();
goods[i][0] = v;//价格
goods[i][1] = p;//重要度
goods[i][2] = q;//主附件
if (q != 0) { //如果是附件,往对应主件的3或4里面填该附件的序号
if (goods[q][3] == 0) { //如果已经是附件1了则标记为附件2
goods[q][3] = i;
} else {
goods[q][4] = i;
}
}
}
/*
for (int i = 0; i <= m; i++) {
System.out.println(Arrays.toString(goods[i]));//这里可看下物品数组
}
*/
int[]vw = new int[money + 1]; //dp数组的简化版(结合视频理解)
for (int i = 1; i <= num; i++) {
if (goods[i][2] == 0) { //如果是主件
//01背包用倒序(结合视频理解)
for (int j = money; j >= goods[i][0]; j--) {
//单主件;vw[j-goods[i][0]]:不拿上一个物品的满意度
vw[j] = Math.max(vw[j], vw[j - goods[i][0]] + goods[i][0] * goods[i][1]);
//有附件1:
if (goods[i][3] != 0 && j >= goods[i][0] + goods[goods[i][3]][0]) {
vw[j] = Math.max(vw[j], vw[j - goods[i][0] - goods[goods[i][3]][0]] +
goods[i][0] * goods[i][1] + goods[goods[i][3]][0] * goods[goods[i][3]][1]);
}
//有附件2
if (goods[i][3] != 0 && j >= goods[i][0] + goods[goods[i][4]][0]) {
vw[j] = Math.max(vw[j], vw[j - goods[i][0] - goods[goods[i][4]][0]] +
goods[i][0] * goods[i][1] + goods[goods[i][4]][0] * goods[goods[i][4]][1]);
}
//有附件1和附件2:
if (goods[i][4] != 0 && j >= goods[i][0] + goods[goods[i][3]][0] + goods[goods[i][4]][0]) {
vw[j] = Math.max(vw[j], vw[j - goods[i][0] - goods[goods[i][3]][0] - goods[goods[i][4]][0]] +
goods[i][0] * goods[i][1] + goods[goods[i][3]][0] * goods[goods[i][3]][1] +
goods[goods[i][4]][0] * goods[goods[i][4]][1]);
}
}
}
//System.out.println(Arrays.toString(vw));//这里可看每一行dp数组
}
System.out.println(vw[money]); //dp数组最后一位即答案
}
}
HJ17 坐标移动
知识点:
正则表达式-菜鸟教程//? 没看呢
Java中的continue语句跳过循环的当前迭代(for,while,do…while等),程序的控制权移到循环的末尾。
continue语句几乎总是在(if ... else语句)决策语句中使用。它的语法是:
continue;
- Java中的break语句立即终止循环,程序的控制权移至循环后的下一条语句。
-
String的方法
String.substring():返回给定字符串的子字符串
string.substring(int startIndex, int endIndex)//下标从0开始String.charAt():返回给定索引处的字符
String.split():将字符串拆分为指定的字符串(正则表达式)
valueOf() 方法用于返回给定参数的原生 Number 对象值,参数可以是原生数据类型, String等。
**Integer valueOf(String s):**返回保存指定的 String 的值的 Integer 对象。
该方法是静态方法。该方法可以接收两个参数一个是字符串,一个是基数。
菜鸟随记:第二次碰到正则表达式了,
复杂度分析
时间复杂度:O(n)O(n)O(n),nnn为输入的字符串长度,不管是正则表达式的匹配还是计算数字,总体上最多遍历字符串每个字符
空间复杂度:O(1)O(1)O(1),正则表达式空间为常数
import java.util.*;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader (new InputStreamReader(System.in));
String[] in = bf.readLine().split(";");
int x = 0;
int y = 0;
for (String s : in) {
//不满足题目给定坐标规则
//合法字符就是ASDW中一个字母后面接上1位或者2位数字,正则表达式为"[WASD][0-9]{1,2}"
if (!s.matches("[WASD][0-9]{1,2}")) { //[]:匹配包含的任一字符;{}:匹配至少 n 次,至多 m 次
continue;//continue:跳到下一次循环;break:跳出当前所在循环
}
int val = Integer.valueOf(s.substring(1)); //valueOf()将参数转换为Integer类型;String.substring()返回给定字符串从指定下标开始的子字符串
switch (s.charAt(0)) { //String.charAt():返回给定索引处的字符
case 'W':
y += val;
break;
case 'S':
y -= val;
break;
case 'A':
x -= val;
break;
case 'D':
x += val;
break;
}
}
System.out.println(x + "," + y);
}
}
#华为机试,emo了#



