位运算的用法
1.二进制中1的个数(输入一个整数n,求这个整数表示的二进制中有多少个1)
思路:1》将n与1做 & 运算,如果n为基数,则结果为1,否则结果为0,这样可以判断n的最低位,每次将n右移一位,则可以计算出n中1的个数。
2》上面的1》只适合n为正数的情况,当n为负数时,n右移时,高位会添加符号位1,这样得到的1的个数就不是我们想要的结果了。既然如此,可以将1右移,然后将得到的数与n做&运算,这样就可以避免负数右移的情况了,因为n可能为负数,所以需要将1左移至最高位为止,当n表示的类型所能表示的最大数有w位时,时间复杂度为O(W)
3》由于n-1相当于将n的最后一个1变成0,然后将该位以后的0全部变成1,所以(n-1)&n会将最后一位1变成0,将(n-1)&n赋值给n,判断n是否是0,如果不是,则说明n中还有1,继续操作。
2.用一条语句判断n时候是2的整数次方
思路:n如果是2的整数次方,则n的二进制表示中只会存在1个1,题目转化成了如何判断n中只有一个1的问题,首先看n是不是0,如果不是0,则(n-1)&n应该等于0.
3. 将整数m变成n需要几步
思路:在十进制中判断是非常困难的,但是如果将m和n转到二进制,就非常容易了。m和n都转为二进制表示后,问m变成n需要多少步,只需要把两个数对应的位置不同的数改为相同就好了,也就是判断m和n有多少位是不同的。将m^n,就可以将m和n中相同的位变成0,不同的位置为1,然后数该结果中1的个数就好。
总结:n&(n-1)的结果,相当于把n的二进制表示中最后一个1变成0
数值的整数次方
这一题后来在滴滴笔试题中遇到了,直接挂了。
1. 实现Power(double base,int exponent):求base的exponet次方。
思路:首先,要考虑各种测试用例情况,如exponent<0;base=exponent=0;exponent>0。第一种情况可以先计算exponent>0的情况,然后计算倒数就好,第二种情况,0的0次方无意义,看题目怎么定义。测试用例考虑好了之后,如果用循环的方法来做这道题,时间复杂度会很高O(n)。由于n次方可以看做是(n/2)次方的平方,可以用递归的方法,每次将exponent折半来求。时间复杂度O(lgn)
public double power(double base, int exponent){
if(exponent==0){
return 1;
}
if(exponent==1){
return base;
}
double result = power(base,exponent>>1);
result=result*result;
//exponent为奇数时,另外将result与base相乘一次,该语句在递归回溯过程中exponent为奇数时调用
if((exponent & 0x1)==1){
result = result*base;
}
return result;
}
用字符串模拟大数字乘法、加法
1. 打印1到最大的n位数(1,2,3.......一直到n个9)
思路:n可能很大,有可能超出int和long能够表示的数值范围,所以用字符串来表示比较合适。用字符数组来模拟数字加法,首先要将每一位字符转化为int类型进行计算,手动判断是否需要进位。
public static void main(String[] args) {
// TODO Auto-generated method stub
int n=2; //打印1到99的数
char[] c=new char[n];
for(int i=0;i<n;i++){
c[i]='0';
}
while(!print1toN(c)){
myprint(c);
}
}
/*
* 用字符数组c来存放中间数字,每次只对最低位加1,如果有进位就继续处理,没有进位就退出,并且用最高位是否有进位来判断是否到最大数
*/
public static boolean print1toN(char []c){
int add=0;
boolean over=false;
for(int i=c.length-1;i>=0;i--){
int s=c[i]-'0'+add;
if(i==c.length-1){ //最低一位加1
s++;
}
if(s>=10){
if(i==0){ //最高位大于等于10,说明溢出了
over=true;
}else{
s=s-10;
add=1;
c[i]=(char) ('0'+s); //更新s的值,并转化为字符
}
}else{
c[i]=(char) ('0'+s);
break; //每次只加1,如果有进位,就处理完进位后退出
}
}
return over;
}
/*
* myprint(char[]) 去掉字符数组中前面为‘0’的字符,只输出我们感兴趣的部分
*/
public static void myprint(char[] c){
//boolean firstzero=true;
int i=0;
for(;i<c.length;i++){
if(c[i]!='0'){
break;
}
}
while(i<c.length){
System.out.print(c[i]);
i++;
}
System.out.println();
}
另一种方法是用全排列的思想来解决。下面的myprint函数就是上面的打印函数。
public static void main(String[] args) {
// TODO Auto-generated method stub
int n=2;
char[] c=new char[n];
for(int i=0;i<n;i++){
c[i]='0';
}
for(int i=0;i<10;i++){ //1到9,各取一次
c[0]=(char) (i+'0');
print1TON(c,n,0);
}
}
public static void print1TON(char[]c,int length,int index){
if(index==length-1){ //index在传入进函数时已经赋值了
myprint(c);
return;
}
for(int i=0;i<10;++i){
c[index+1]=(char) (i+'0'); //右面一位也是1到9各取一次
print1TON(c,length,index+1);
}
}
二叉树中的递归+栈处理
25. 打印二叉树中路径和为s的所有路径
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
一直对递归和DFS的应用不太懂,这一题都设计到了,写过两三遍,还是不能自己独立写出来。在网上找了一些资料,也都看过,对解答还是有点模糊。
问题如下:1. 路径符合时,需要将list加入到result中,为什么不能直接加list,而是加了一个new ArrayList<Integer> (list)
import java.util.ArrayList;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer>>result = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list=new ArrayList<Integer>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
if(root==null){
return result;
}
list.add(root.val);
target=target-root.val;
if(target==0 && root.left==null && root.right==null){
result.add( new ArrayList<Integer> (list));
}else{
if(root.left!=null){
FindPath(root.left,target);
list.remove(list.size()-1);
}
// list.remove(list.size()-1);
if(root.right!=null){
FindPath(root.right,target);
list.remove(list.size()-1);
}
}
return result;
}
}