剑指offer 11-15

11 二进制中1的个数

  输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示

分析

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

(搬运评论区大佬的解释)
如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

public class numberOfBinary_11 {

    public static void main(String[] args) {
        numberOfBinary_11 sum = new numberOfBinary_11();
        int res = sum.NumberOf1(10);
        System.out.println(res);
    }
    public int NumberOf1(int n) {
        if(n == 0) {
            return 0;
        }
        int count = 0;
        while(n != 0) {
            count++;
            n = n & (n-1);
        }
        return count;
    }
}

12 数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0
//1 直接运算 时间复杂度:O(n),其中n为所求的次方数,一共需要乘n次
public double Power(double base, int exponent) {
      if(exponent == 0) return 1;
      double res = 1;
      for(int i = 1; i <= Math.abs(exponent); i++){
        res = res * base;
      }
      if(exponent < 0) return 1 / res;
      return res;
        
  }
//2 方法二:快速幂(扩展思路)

// 知识点:分治:
/*计算幂运算,我们还可以使用快速幂快速计算。 如果我们要计算5105^{10}510,常规的算法是5∗5=255*5=255∗5=25,
然后再25∗5=12525*5=12525∗5=125,如此往下,一共是999次运算,即n−1n-1n−1次。但是我们可以考虑这样:5∗5=255*5=255∗5=25(二次)、
25∗25=62525*25=62525∗25=625(四次)、625∗625=...625*625=...625∗625=...(八次),这是一个二分的思维,运算次数缩减到了log2nlog_2nlog2​n次
*/ public class Solution { //快速幂 private double Pow(double x, int y){ double res = 1; while(y != 0){ //可以再往上乘一个 if((y & 1) != 0) res *= x; //叠加 x *= x; //减少乘次数 y = y >> 1; } return res; } public double Power(double base, int exponent) { //处理负数次方 if(exponent < 0){ base = 1 / base; exponent = -exponent; } return Pow(base, exponent); } }

 

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

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

public class adjustArrays_13 {

    public static void main(String[] args) {
        adjustArrays_13 adjust = new adjustArrays_13();
        int[] array = {1,2,3,4,6,8,9,11};
        int[] arr = adjust.reOrderArray(array);
         for(int i : array) {
                 System.out.println(i);
             }
    }
    public int[] reOrderArray(int[] array) {
        int[] reArray1 = new int[array.length];
        int[] reArray2 = new int[array.length];
        int m=0;
        int n=0;
        for(int i=0;i<array.length;i++){
            if(array[i]%2!=0){
                reArray1[m++]=array[i];
            }
             if(array[i]%2==0){
                reArray2[n++]=array[i];
            }
        }
        for(int i=0;i<m;i++){
            array[i]=reArray1[i];
        }
         for(int i=0;i<n;i++){
            array[i+m]=reArray2[i];
        }
        return array;
    }
    }

还有另外一种方法

  • i++往前走碰到偶数停下来,j = i+1
  • a[j]为偶数,j++前进,直到碰到奇数如果j==len-1时还没碰到奇数,证明ij之间都为偶数了,完成整个移动
  • a[j]对应的奇数插到a[i]位置,j经过的j-i个偶数依次后移

 

public int[] reOrderArray2(int[] array) {
        int len = array.length;
                if(len <= 1){ // 数组空或长度为1
                    return null;
                }

                int i = 0;
                while(i < len){
                    int j = i + 1;
                    if(array[i]%2 == 0){ // a[i]为偶数,j前进,直到替换
                        while(array[j]%2 == 0){ // j为偶数,前进
                            if(j==len-1)// i为偶数,j也为偶数,一直后移到了末尾,证明后面都是偶数
                                 return array;
                            j++;
                        }
                        // 此时j为奇数
                        int count = j-i;
                        int temp = array[i];
                        array[i] = array[j];
                        while(count>1){
                            array[i+count] = array[i+count-1];//数组后移
                            count--;
                        }
                        array[i+1] = temp;
                    }
                    i++;
                }
                return array;
            }

14 链表中倒数第K个结点

  输入一个链表,输出该链表中倒数第k个结点

 

分析:

快指针先往前走k步,注意判断边界,然后快慢一起走,当快指针为none的时候,慢指针走到了倒数第k个节点

 

package list;

import java.util.Scanner;

public class findKthToTail_14 {

    public static void main(String[] args) {
        ListNode2 l = new ListNode2(-1);
        ListNode2 l1 = l;
        Scanner s = new Scanner(System.in);
        while (!s.hasNext("!")) {
            l1.next = new ListNode2(s.nextInt());
            l1 = l1.next;
        }
        ListNode2 node  = FindKthToTail(l.next, 2);
        System.out.println(node.val);
    }
    //快指针先往前走k步,注意判断边界,然后快慢一起走,当快指针为none的时候,慢指针走到了倒数第k个节点
    public static ListNode2 FindKthToTail(ListNode2 head,int k) {
        if(k <= 0 || head == null) {
            return null;
        }
        ListNode2 fast = head;
        ListNode2 slow = head;
        for(int i = 0; i < k; i++) {
            if(fast == null) {
                return null;
            }
            fast = fast.next;
        }
        while(fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }

}
class ListNode2{
    int val;
    ListNode2 next;
    public ListNode2(int val) {
        this.val = val;
    }
}

 

 

 

15 反转链表

  输入一个链表,反转链表后,输出新链表的表头。

分析

    • 题目所给的是单链表,想了一下反转后的样子:最后一个结点指向倒数第二个,倒数第二个指向倒数第三个,......,第二个指向第一个,第一个指向null;
    • 知道了反转后各个结点指向哪之后,就需要开始调整每个结点的next指针。
    • 这就需要把结点挨个从链表上摘下来,做调整;
    • 这个调整过程需要两个指针辅助:pre记录其前一个结点位置,好让该结点的next指针指向前一个结点,但是在指向前一个结点前需要用一个指针p记录后一个结点地址,避免结点丢失。
    • 例子:
      • 以head结点为例步骤如下:
      • 1.反转后head是指向null,所以未反转的时候其前一个结点应该是null,初始化pre指针为null;
      • 2.用p指针记录head的下一个结点head.next;
      • 3.从链表上摘下head,即让head.next指向pre;
      • 4.此时已完成head结点的摘取及与前一个节点的连接,则我们需要操作下一个结点:故需移动pre和head,让pre指向head,head指向下一个节点。
      • 重复这四个操作直到head走完原链表,指向null时,循环结束,返回pre.

注:上文的p在代码中为next;

 

package list;

import java.util.Scanner;

public class reverseList_15 {

    public static void main(String[] args) {
        ListNode3 l = new ListNode3(-1);
        ListNode3 l1 = l;
        Scanner s = new Scanner(System.in);
        while (!s.hasNext("!")) {
            l1.next = new ListNode3(s.nextInt());
            l1 = l1.next;
        }

        ListNode3 node = ReverseList(l.next);
        while (node != null) {
            System.out.print(node.val + " ");
            node = node.next;
        }
    }

    public static ListNode3 ReverseList(ListNode3 head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode3 pre = null;
        ListNode3 next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

}

class ListNode3 {
    int val;
    ListNode3 next;

    public ListNode3(int val) {
        this.val = val;
    }

}

 

posted @ 2020-05-26 14:02  我们村里的小花儿  阅读(145)  评论(0编辑  收藏  举报