一.进制
今天对进制有了新的理解,拿最常见的十进制,我们求每一个位时都用n%10,n/10反复循环直到n==0,对于其他进制也一样,都拿对应的数进行这样的操作(数是一定的,进制不同呈现的样子也不同)。
案例一:判断是不是sky数
skys数,如果n的十进制、十二进制、十六进制的四位数相加的和都相同
import java.util.ArrayList;
import java.util.Scanner;
public class 进制练习sky数 {
public static void main(String[] args) {
//skys数,如果n的十进制、十二进制、十六进制的四位数相加的和都相同
//判断是不是sky数
Scanner sc=new Scanner(System.in);
//方法一(且对多个数判断,以0来停止数输入)
ArrayList<Integer> list=new ArrayList<>();
while (true){
int n=sc.nextInt();
if(n==0){
break;
}
if(n<10000){
list.add(n);
}
}
for(int j=0;j<list.size();j++){
int[]arr={10,12,16};
int[]arr1=new int[3];
for(int i=0;i<arr.length;i++){
int temp=list.get(j);
int count=0;
while (temp!=0){
count=count+temp%arr[i];
temp=temp/arr[i];
arr1[i]=count;
}
}
if (arr1[0]==arr1[1]&&arr1[1]==arr1[2]){
System.out.println(list.get(j)+" is a Sky Number.");
}else {
System.out.println(list.get(j)+" is not a Sky Number.");
}
}
}
}
这道题,一般思路是将数分别转化为对应的进制的字符串,再将每个字符提取出来根据Ascall码来计算,然后再相互比较,但是这样的编码长且重复且复杂。
但是通过对进制的理解,可以用一个循环用相应的进制数对n%x,n/x进行反复循环并将其余数相加就是所有位数和。
案例二:集合求子集
public class Main {
public static void main(String[] args) {
//给定一个集合求它的所有子集
int[]arr={1,2,3,4};
//放到相应的二进制里
for(int i=0;i<=Math.pow(2,4)-1;i++){
String s=Integer.toString(i,2);
String len="{";
for (int j=0;j<s.length();j++){
if(s.charAt(j)=='1'){
len=len+arr[j]+" ";
}
}
len=len+"}";
System.out.println(len);
}
}
}
这道题最最最最最最关键的思路就在于把这个集合放入二进制中,如集合[1,2,3,4]对应的二进制为0000到1111,再创建数组通过循环嵌套可以将所有子集情况都输出。
最关键的核心思想就是和二进制结合,也考验了对进制的理解
二.位运算
&且、|或、^异或都是用两个数的二进制进行计算 最后重新排列组成二进制,再将二进制转化为10进制输出
&:如果同位都为1则1,不然则0
System.out.println(7%3);//3
|:有1就1,没1就0
System.out.println(7|3);//7
^:如果相同则0,不同则1,可以用于两数交换
System.out.println(7^0);//7
案例一:给定一个数n,判断是否非2的n次;(对&的掌握)
import java.util.Scanner;
public class 位运算实践1 {
public static void main(String[] args) {
//给定一个数n,判断是否非2的n次;
Scanner sc = new Scanner(System.in);
//正常方法有很多,比如一直除以2,下面是两种简单快捷的方式
//两种新的思维,对进制和位运算的掌握
//1.位运算(重点)
int a = sc.nextInt();
System.out.println((a & (a - 1)) == '0' ? "YES" : "NO");
}
}
&将数变成二进制展开,相应位置都为一则一,不然则0。根据这个性质可以推出a=a & (a - 1))作用是把最右边的那个1变为零,根据这个特性我们把其放在循环里配合count就能求出1的个数,如果大于1则说明n不是2的次方。
案例二:求n的二进制有多少个1
import java.util.Scanner;
public class 位运算实践2 {
public static void main(String[] args) {
//求整数n的二进制中有多少个1
//常用方法:1.n->2进制,用for循环统计里面的1的个数
// 2.把循环n%2,n/2 求有多少个1余下
//位运算
//&相应为都为1才是1
//a&(a-1)的作用是把a二进制最右边的1变成0(自己再思考一下,不能死记)
Scanner sc=new Scanner(System.in);
int a=sc.nextInt();
int count=0;
while (a!=0){
a=a&(a-1);//做一次,就是把a的最右边的1变成0
count++;//计数
}
System.out.println(count);
}
}
与第一题同理,&将数变成二进制展开,相应位置都为一则一,不然则0。根据这个性质可以推出a=a & (a - 1))作用是把最右边的那个1变为零,根据这个特性我们把其放在循环里配合count就能求出1的个数。
案例三:异或位运算,求一组数中只出现了一遍的数
异或^t特性:
a^b^j^k^l^i与a^l^j^b^k^i相同
i^i=0 i^0=i
import java.util.Scanner;
public class 位运算3异或位运算 {
public static void main(String[] args) {
//异或^
//a^b^j^k^l^i与a^l^j^b^k^i相同
//i^i=0 i^0=i
//求只出现一次的数
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int asc=0;
for(int i=0;i<2*n-1;i++){
asc=asc^sc.nextInt();
}
System.out.println(asc);
}
}
掌握了这些特性,可以知道如果重复了的数通过异或符号为零,而只出现了一遍的数^0则等于本身,那么我们只需要将所有数共同异或,并最后异或0就能得到只出现了一次的数。
pass:小技巧
由于int和String都可以通过Integer进行转化,但是由于比较大的进制每一位可能是英文,所以转化时int只接收10进制、String接收其他进制,所以如果要准化成其他进制用Integer.toString转化为对应进制字符串,反之转化成10进制则用Integer.parseInt();转化成10进制int.