程序员面试题解记录

本文探讨了Java编程中的一些关键算法,包括如何使用DFS遍历树并计算路径数量,以及位操作的应用,如插入位、反转位和交换位。文章通过实例详细解释了这些操作的实现逻辑,并强调了类型转换和递归在解决问题中的重要性。此外,还提到了列表操作的陷阱,以及解决方法。
摘要由CSDN通过智能技术生成

05.01 

class Solution {
    public int insertBits(int N, int M, int i, int j) {
       int left=N>>j>>1;
       left=left<<j<<1;
       int mid=M<<i;
       int last=N&((1<<i)-1);//取一个数低位的方法,1左移i位后减一,得到一个i位全为1的数,再与原数与
       return left | mid | last; 

    }
}

 0412

class Solution {
    int ans=0;
    public int pathSum(TreeNode root, int sum) {
        if(root==null) return 0;
        dfs(root,0,sum);
        if(root.left != null) pathSum(root.left,sum);
        if(root.right != null) pathSum(root.right,sum);
        return ans;
    }
    public void dfs(TreeNode root,int S, int sum){
        if(root==null) return;
        if(S+root.val==sum) ans++;
        dfs(root.left,S+root.val,sum);
        dfs(root.right,S+root.val,sum);
    }
}
/**树的深度优先遍历等于先序遍历 */

这里考察了dfs的用法,dfs类似先序遍历,它的原则是从根节点出发,只要存在路径就一直走下去,直到root等于null才返回上一层,寻找是否有其他路径可以走。

利用dfs求路径的条数,我们把每一个节点都看作一个根节点,对其进行dfs。

0503、2476

class Solution {
    public  int reverseBits(int num) {
        String s=Integer.toBinaryString(num);
        int result=0,pre=0,cur=0;
        for(int i=0;i<s.length();i++){
            if((int)s.charAt(i)-'0'==1){
                pre++;
            }else{
                cur=pre;
                pre=0;
            }
            result=Math.max(pre+cur+1,result);
        }
        return result==33?32:result;
    }
}

这道题的逻辑很好理解,运动了动态规划的思想。用cur记录0之前的1个数,用pre记录遇到下一个0之前的1个数。

算了一个小时的原因在于类型转换不了解,转换过程是int——》String——》char——》int

在char型数字与int型比较时,要注意char型数字返回值是ASCII码,比如char 0ASCII码为48。

当前字符减去字符0 ,得到当前字符的int值。

0506/2478

class Solution {
    public int convertInteger(int A, int B) {
//运用异或的思想,将a与b异或,得到不同位为1,再求1的个数
    int result=A^B;
    int i=0;
    while(result!=0){
        result=result&(result-1);
        i++;
    }
    return i;
    }
}

n-1的话,会一直向前寻找可借的位,从而跳过低位连续的0,而向最低位的1借位,借位后最低位的1变为0,原先最低位1的下一位从0变为1,其余位都不变,相与之后其它位不变,1(最低位1)0 &01(n-1对应的位)= 00,从而消除最低位的1。

0507\2479

class Solution {
    public int exchangeBits(int num) {
        return ((num &  0x55555555)<<1) | ((num & 0xaaaaaaaa)>>1);
    }
}

int -> 32位

奇数位全1 -> 0101.... 表示为 0x55555555

偶数位全1 -> 1010.... 表示为 0xaaaaaaaa

0508

int 数据类型是4个字节,32位。而一个非黑即白(0/1)表示的像素点就是一位。

0804、2484

抛去动态规划的思想不谈,一开始的代码是这个样子。

public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> lists=new ArrayList<>();
        lists.add(new ArrayList<>());
        for(int n : nums){
            int size=lists.size();
            for(int i=0;i<size;i++){
                List<Integer> ls=new ArrayList();
                ls=lists.get(i);
                ls.add(n);
                lists.add(ls);
            }
        }
        return lists;
    }

怎么读逻辑都是对的,但控制台输出为

 又在idea中debug了一遍,运行步骤也没有错误。但可以观察到lists中元素始终只有一个,ls没有new成功,添加n也只是在lists中添加。

察觉到了可能的错误,list是不是不能用list赋值?

搜索发现:java中使用list1=list的赋值方式使得list1和list2指向同一个内存地址,两者会同时改变。

于是修改代码,用addAll();

public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> lists=new ArrayList<>();
        lists.add(new ArrayList<>());

        for(int i = 0; i < nums.length; i++){
            int size=lists.size();
            for(int j=0;j<size;j++){
                List<Integer> ls=new ArrayList<>();
                ls.addAll(lists.get(i));
                ls.add(nums[i]);
                lists.add(ls);
            }
        }
        return lists;
    }

0806、2492

经典汉诺塔问题。

递归定义为:一个大的问题其实是由操作相同的小问题不断重复完成的。

递归的核心:

1.递归出口

2.重复做的事是什么

那么回答关于递归的两个问题

1.当盘子只有一个时,即最初的情况,直接将盘子从A移动到C。

2.它重复执行的步骤为:

1.将n-1个盘子从A移到B

2.将最大的盘子从A移到C

3.将n-1个盘子从B移到C(其实1与3做的重复相同)

0807、2506

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值