11、二进制中1的个数

  1. 输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示
  • 解法一

    • 找一个标志位1,从最右边开始和这个二进制数做&运算,每个不为0的与结果就表明出现了一个1
      1. public class Solution {
      2. public int NumberOf(int n) {
      3. int t = 0;
      4. int flag = 1;
      5. while(flag != 0){
      6. if((n&flag)!=0){
      7. t++;
      8. }
      9. flag = flag << 1; //当位运算到最大值(32位)时,回到0,跳出循环
      10. }
      11. return t;
      12. }
      13. }
  • 解法二

    1. 一个二进制数1100,从右边数起第三位是处于最右边的一个1,
    2. 减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,
    3. 因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。
    4. 这个时候如果我们再把原来的整数和减去1之后的结果做与运算,
    5. 从原来整数最右边一个1那一位开始所有位都会变成0
    6. 1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0
    7. 那么一个整数的二进制有多少个1,就可以进行多少次这样的操作
    1. public class Solution {
    2. public int NumberOf(int n) {
    3. int t=0;
    4. while(n != 0){
    5. t++;
    6. n=n&(n-1);
    7. }
    8. return t;
    9. }
    10. }


    12、数值的整数次方

    1. 给定一个double类型的浮点数baseint类型的整数exponent。求baseexponent次方
    2. 保证baseexponent不同时为0。不得使用库函数,同时不需要考虑大数问题,也不用考虑小数点后面0的位数
  • 解法一

    • 直接暴力求解
    • 先对指数进行处理,指数为负数,则底数base变成1/base,exponent=-exponent
      1. public class Solution {
      2. public double Power(double base, int exponent) {
      3. if(exponent<0){
      4. base = 1/base;
      5. exponent = -exponent;
      6. }
      7. double result = 1;
      8. for(int i=0;i<exponent;i++){
      9. result = result*base;
      10. }
      11. return result;
      12. }
      13. }
  • 解法二

    • 主要是讨论指数大于0,等于0,小于0 以及底数为0时 的情况
      1. /**
      2. * 1.全面考察指数的正负、底数是否为零等情况
      3. * 2.写出指数的二进制表达,例如13表达为二进制1101
      4. * 3.举例:10^1101 = 10^0001 * 10^0100 * 10^1000
      5. * 4.通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果
      6. */
      1. public class Solution {
      2. public double Power(double base, int exponent) {
      3. double res = 1,curr = base;
      4. int temp; //temp对指数进行处理,若为负数,转换为正指数
      5. if(exponent>0){
      6. temp = exponent;
      7. }else if(exponent<0){
      8. if(base==0)
      9. throw new RuntimeException("分母不能为0");
      10. temp = -exponent;
      11. }else{// exponent==0
      12. return 1;// 0的0次方
      13. }
      14. while(temp!=0){
      15. if((temp&1)==1)
      16. res*=curr;
      17. curr*=curr;// 翻倍
      18. temp>>=1;// 右移一位
      19. }
      20. return exponent>=0?res:(1/res);
      21. }
      22. }

      13、调整数组顺序使奇数位于偶数前面

      1. 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,
      2. 使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,
      3. 并保证奇数和奇数,偶数和偶数之间的相对位置不变
  • 解法一

    • 使用辅助数据,遍历数组,将奇数添加到数据里面;再次遍历数组,将偶数添加到数组里面
      1. import java.util.*;
      2. public class Solution {
      3. /**
      4. * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
      5. * @param array int整型一维数组
      6. * @return int整型一维数组
      7. */
      8. public int[] reOrderArray (int[] array) {
      9. // write code here
      10. int[] temp = new int[array.length];
      11. int t = 0;
      12. for(int i=0;i<array.length;i++){
      13. if(array[i]%2 == 1){
      14. temp[t++] = array[i];
      15. }
      16. }
      17. for(int i=0;i<array.length;i++){
      18. if(array[i]%2 == 0){
      19. temp[t++] = array[i];
      20. }
      21. }
      22. return temp;
      23. }
      24. }

      14、链表中倒数第k个结点

      1. 输入一个链表,输出该链表中倒数第k个结点
      2. 如果该链表长度小于k,请返回空
  • 解法一,遍历列表,通过算术计算出这是正数第几个结点 ```java import java.util.; /

    • public class ListNode {
    • int val;
    • ListNode next = null;
    • public ListNode(int val) {
    • this.val = val;
    • }
    • } */

public class Solution { /**

  1. * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
  2. * @param pHead ListNode
  3. * @param k int整型
  4. * @return ListNode
  5. */
  6. public ListNode FindKthToTail (ListNode pHead, int k) {
  7. // write code here
  8. int length = 0;
  9. ListNode temp = pHead;
  10. while(temp != null){
  11. length++;
  12. temp = temp.next;
  13. }
  14. if(length < k){
  15. return null;
  16. }
  17. int key = length - k;
  18. temp = pHead;
  19. while(key>0){
  20. temp = temp.next;
  21. key--;
  22. }
  23. return temp;
  24. }

}

  1. - 解法二
  2. - 快慢指针,快指针先走k步,假如还未到k步就为空,就返回空;否则,在快指针走了k步后,快慢指针同时走,直到快指针为空,返回慢指针
  3. ```java
  4. import java.util.*;
  5. /*
  6. * public class ListNode {
  7. * int val;
  8. * ListNode next = null;
  9. * public ListNode(int val) {
  10. * this.val = val;
  11. * }
  12. * }
  13. */
  14. public class Solution {
  15. /**
  16. * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
  17. * @param pHead ListNode类
  18. * @param k int整型
  19. * @return ListNode类
  20. */
  21. public ListNode FindKthToTail (ListNode pHead, int k) {
  22. // write code here
  23. if(pHead == null){
  24. return pHead;
  25. }
  26. ListNode fast = pHead;
  27. int i = 0;
  28. while(i < k){
  29. if(fast == null){
  30. return fast;
  31. }
  32. i++;
  33. fast = fast.next;
  34. }
  35. ListNode slow = pHead;
  36. while(fast != null){
  37. fast = fast.next;
  38. slow = slow.next;
  39. }
  40. return slow;
  41. }
  42. }

15、反转链表

  1. 输入一个链表,反转链表后,输出新链表的表头
  • 解法一

    • 定义三个指针,第1个指针和第2个指针为待处理指针指向的前后指针,第3个指针为正准备处理的链表尾部

      1. /*
      2. public class ListNode {
      3. int val;
      4. ListNode next = null;
      5. ListNode(int val) {
      6. this.val = val;
      7. }
      8. }*/
      9. public class Solution {
      10. public ListNode ReverseList(ListNode head) {
      11. if(head == null){
      12. return head;
      13. }
      14. ListNode left = head;
      15. ListNode mid = left.next;
      16. if(mid == null){
      17. return head;
      18. }
      19. ListNode right = mid.next;
      20. head.next = null;
      21. while(right != null){
      22. mid.next = left;
      23. left = mid;
      24. mid = right;
      25. right = right.next;
      26. }
      27. mid.next = left;
      28. return mid;
      29. }
      30. }
  • 与解法一类似,更巧妙

    1. /*
    2. public class ListNode {
    3. int val;
    4. ListNode next = null;
    5. ListNode(int val) {
    6. this.val = val;
    7. }
    8. }*/
    9. public class Solution {
    10. public ListNode ReverseList(ListNode head) {
    11. if(head==null)
    12. return null;
    13. ListNode pre = null;
    14. ListNode next = null;
    15. while(head!=null){
    16. next = head.next;
    17. head.next = pre;
    18. pre = head;
    19. head = next;
    20. }
    21. return pre;
    22. }
    23. }

    16、合并两个排序的链表

    1. 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则
  • 解法一

    • 递归:怎么理解呢,为啥想不上来
    • 从两个头结点中取出小数,那么它的下一个结点就是剩下的链表继续合并,跳出递归是:list1为空,返回剩下的list2;list2为空,返回的是剩下的list1

      1. /*
      2. public class ListNode {
      3. int val;
      4. ListNode next = null;
      5. ListNode(int val) {
      6. this.val = val;
      7. }
      8. }*/
      9. public class Solution {
      10. public ListNode Merge(ListNode list1,ListNode list2) {
      11. if(list1 == null){
      12. return list2;
      13. }
      14. if(list2 == null){
      15. return list1;
      16. }
      17. if(list1.val <= list2.val){
      18. list1.next = Merge(list1.next,list2);
      19. return list1;
      20. }else{
      21. list2.next = Merge(list1,list2.next);
      22. return list2;
      23. }
      24. }
      25. }
  • 解法二

    • 合并时,每次取出链表小的结点,最后将剩下的不为空的链表接上去即可
      1. public class Solution {
      2. public ListNode Merge(ListNode list1,ListNode list2) {
      3. //注意传入参数就为空,参数在后端来说,都是不被信任的
      4. if(list1 == null){
      5. return list2;
      6. }
      7. if(list2 == null){
      8. return list1;
      9. }
      10. ListNode head = null; //合并后头指针
      11. ListNode current = null; //正在处理的结点指针
      12. if(list1.val <= list2.val){ //找到头指针
      13. head = current = list1;
      14. list1 = list1.next;
      15. }else{
      16. head = current = list2;
      17. list2 = list2.next;
      18. }
      19. while(list1 != null && list2!= null){
      20. if(list1.val <= list2.val){
      21. current.next = list1;
      22. list1 = list1.next;
      23. current = current.next; //注意正在处理指针后移
      24. }else{
      25. current.next = list2;
      26. list2 = list2.next;
      27. current = current.next;
      28. }
      29. }
      30. if(list1 != null){
      31. current.next = list1;
      32. }
      33. if(list2 != null){
      34. current.next = list2;
      35. }
      36. return head;
      37. }
      38. }

      17、树的子结构

      1. 输入两棵二叉树AB,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
  • 什么时候是子结构的开始

  • 树问题解法好多需要递归来解决

    • 比较根节点,比较左子树,比较右子树

      1. /**
      2. public class TreeNode {
      3. int val = 0;
      4. TreeNode left = null;
      5. TreeNode right = null;
      6. public TreeNode(int val) {
      7. this.val = val;
      8. }
      9. }
      10. */
      11. public class Solution {
      12. public boolean HasSubtree(TreeNode root1,TreeNode root2) {
      13. boolean result = false;
      14. //当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
      15. if (root2 != null && root1 != null) {
      16. //如果找到了对应Tree2的根节点的点
      17. if(root1.val == root2.val){
      18. //以这个根节点为为起点判断是否包含Tree2
      19. result = doTree1HaveTree2(root1,root2);
      20. }
      21. //如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2
      22. if (!result) {
      23. result = HasSubtree(root1.left,root2);
      24. }
      25. //如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2
      26. if (!result) {
      27. result = HasSubtree(root1.right,root2);
      28. }
      29. }
      30. //返回结果
      31. return result;
      32. }
      33. public static boolean doTree1HaveTree2(TreeNode node1, TreeNode node2) {
      34. //如果Tree2已经遍历完了都能对应的上,返回true
      35. if (node2 == null) {
      36. return true;
      37. }
      38. //如果Tree2还没有遍历完,Tree1却遍历完了。返回false
      39. if (node1 == null) {
      40. return false;
      41. }
      42. //如果其中有一个点没有对应上,返回false
      43. if (node1.val != node2.val) {
      44. return false;
      45. }
      46. //如果根节点对应的上,那么就分别去子节点里面匹配
      47. return doTree1HaveTree2(node1.left,node2.left) && doTree1HaveTree2(node1.right,node2.right);
      48. }
      49. }

      18、二叉树的镜像

      1. 操作给定的二叉树,将其变换为源二叉树的镜像

      image.png

  • 解法

    • 使用递归
      • 先判断根节点,若根节点为null或者是单个结点则直接返回
      • 处理根节点的左子树
      • 处理根节点的右子树 ```java import java.util.*;

/*

  • public class TreeNode {
  • int val = 0;
  • TreeNode left = null;
  • TreeNode right = null;
  • public TreeNode(int val) {
  • this.val = val;
  • }
  • } */

public class Solution { /**

  1. * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
  2. * @param pRoot TreeNode
  3. * @return TreeNode
  4. */
  5. public TreeNode Mirror (TreeNode pRoot) {
  6. // 递归结束条件
  7. if(pRoot == null){
  8. return pRoot;
  9. }
  10. if(pRoot.left == null && pRoot.right == null){
  11. return pRoot;
  12. }
  13. // 交换根节点的左右儿子
  14. TreeNode temp = pRoot.left;
  15. pRoot.left = pRoot.right;
  16. pRoot.right = temp;
  17. Mirror(pRoot.left);
  18. Mirror(pRoot.right);
  19. return pRoot;
  20. }

}

  1. <a name="bcTrz"></a>
  2. # 19、顺时针打印矩阵
  3. ```java
  4. 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字
  5. 例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  6. 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10
  • 解法

    • 定义四个变量表示边界范围,其中up、down表示上下边界,left、right表示左右边界。不断收缩边界范围
      • 首先向右遍历,将找到的数加入到集合中,并且边界值up++,如果边界值up大于down,跳出循环
      • 其次向下遍历,将找到的数加入到集合中,并且边界值right—,如果边界值left大于right,跳出循环
      • 其次向左遍历,将找到的数加入到集合中,并且边界值down—,如果边界值up大于down,跳出循环
      • 最后向上遍历,将找到的数加入到集合中,并且边界值left++,如果边界值left大于right,跳出循环
      • 循环遍历下去
        1. import java.util.ArrayList;
        2. public class Solution {
        3. public ArrayList<Integer> printMatrix(int [][] matrix) {
        4. ArrayList<Integer> list = new ArrayList<>();
        5. if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
        6. return list;
        7. }
        8. int up = 0;
        9. int down = matrix.length - 1;
        10. int left = 0;
        11. int right = matrix[0].length - 1;
        12. while(true){
        13. for(int col = left; col<=right;col++){
        14. list.add(matrix[up][col]);
        15. }
        16. up++;
        17. if(up > down){
        18. break;
        19. }
        20. for(int row = up; row<=down;row++){
        21. list.add(matrix[row][right]);
        22. }
        23. right--;
        24. if(left > right){
        25. break;
        26. }
        27. for(int col = right; col>=left;col--){
        28. list.add(matrix[down][col]);
        29. }
        30. down--;
        31. if(up > down){
        32. break;
        33. }
        34. for(int row = down; row>=up;row--){
        35. list.add(matrix[row][left]);
        36. }
        37. left++;
        38. if(left > right){
        39. break;
        40. }
        41. }
        42. return list;
        43. }
        44. }

        20、包含min函数的栈

        1. 定义栈的数据结构,
        2. 请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O1))
  • 用空间换时间

    • 使用一个辅助栈minStack来存最小值
      • 如果此时的数据小于minStack的栈顶,则允许存入该值,否则把minStack的栈顶重新存一遍到minStack
      • push,push数据到stack;如果辅助栈minStack为null,则数据push到minStack,否则 数据小于minStack的栈顶时,则允许存入该值,不然把minStack的栈顶重新存一遍到minStack
      • pop,直接弹出两个栈
      • top,返回stack的栈顶
      • min,返回minStack的栈顶 ```java import java.util.Stack;

public class Solution {

  1. private static Stack<Integer> stack = new Stack<Integer>();
  2. private static Stack<Integer> minStack = new Stack<Integer>();
  3. public void push(int node) {
  4. stack.push(node);
  5. if(minStack.empty()){
  6. minStack.push(node);
  7. }else{
  8. if(node <= minStack.peek()){
  9. minStack.push(node);
  10. }else{
  11. minStack.push(minStack.peek());
  12. }
  13. }
  14. }
  15. public void pop() {
  16. stack.pop();
  17. minStack.pop(); //弹出栈顶,做删除
  18. }
  19. public int top() {
  20. return stack.peek(); //弹出栈顶,不做删除
  21. }
  22. public int min() {
  23. return minStack.peek();
  24. }

} ```