• 剑指Offer系列之题11~题15


    11.矩形覆盖

    我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
    比如n=3时,2*3的矩形块有3种覆盖方法:
    矩形覆盖题目

    斐波那契数列的应用

    第一次竖着放一块类比为走一步,第一次横着放两块类比为走两步


    代码与上面的斐波那契数列类题目类似,此处不再赘述;剑指Offer系列之题6~题10

    12.二进制中1的个数

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

    除法运算比移位运算效率低的多,应尽可能用移位运算代替乘除法。

    对一个数减1,会导致其最右边的1变为0,在该1后面的0全变为1;然后将减1后的数与原数相与,则令原数最右边的1变为0。根据这个思路,与操作可以进行多少次,便是多少个1.


    1.进行它的位数次 与操作 判断1:

    public class Solution {
        public int NumberOf1(int n) {
            //正数的原码、反码、补码都相同;负数的反码是原码按位取反,补码是原码按位取反(符号位不变),最后+1
            int count=0;
            int flag=1;
            while(flag!=0){
                if((n & flag)!=0){//与运算不为0,证明n的该位是1
                    count++;
                }
                flag=flag <<1;//flag左移1位,判断n的下一位是否为1
    
            }
            return count;
        }
    }
    

    2.减1后相与:

    public class Solution {
        public int NumberOf1(int n) {
            //正数的原码、反码、补码都相同;负数的反码是原码按位取反,补码是原码按位取反(符号位不变),最后+1
            int count=0;
            int flag=1;
            while(n!=0){
                n=n&(n-1);//将最右边一位1与之后的位都变为0;5&4即0110&0100,得0100
                count++;
            }
            return count;
        }
    }
    

    13. 数值的整数次方

    给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0。

    double类型的值的次方不能以普通的相乘形式求出


    1.普通解法:

    public class Solution {
        public double Power(double base, int exponent) {
            //指数为正,负
            if(base==0)
                return 0;
            if(exponent==0){
                return 1;
            }
            boolean flag=false;
            if(exponent<0){//负指数
                exponent=-exponent;
                flag=true;
            }
            double res=1.0;
            for(int i=0;i<exponent;i++){
                res*=base;
            }
            if(flag){
                res=1.0/res;
            }
            return res;
      }
    }
    

    2.利用奇偶的n/2相乘递归:

    public class Solution {
        public double Power(double base, int exponent) {
            //指数为正,负
            if(base==0){
                return 0;
            }
            if(exponent==0){
                return 1;
            }
            if(exponent==1){
                return base;
            }
            if(exponent<0){//当指数为负指数
                base=1/base;
                exponent=-exponent;
            }
            //递归
            double res=Power(base,exponent >>>1 );//求出n/2
            //判断奇偶,奇数:a^n=a^(n/2)*a^(n/2)*a,偶数:a^n=a^(n/2)*a^(n/2)
            res*=res;
            if((exponent & 1)==1){
                //奇数
                res*=base;
            }
            return res;
      }
    }
    

    3.快速幂迭代:

    假设求3^13 ,13的二进制位1101,3^13 = 3^8 * 3^4 * 3^1

    从最右边开始与运算(利用位运算进行移位):

    第一位是1,该位的值是3^1 ,则res=res*base;base=base*base(该步求出下一位的值)

    第二位是0,该位的值是3^2 ,因为0所以不参与运算,只求出下一位的值,base*=base;

    第三位是1,该位的值是3^4 ,则res=res*base(此时base的值是3^4);base*=base;

    第四位是1,该位的值是3^8 ,则res=res*base(此时base的值是3^8);base*=base;

    退出循环。

    public class Solution {
        public double Power(double base, int exponent) {
            if(base==0)
                return 0;
            if(exponent==0)
                return 1;
            long n=exponent;
            if(n<0){//当指数为负指数
                base=1/base;
                n=-n;
            }
            double res=1.0;
            while(n>0){
                if((n & 1)==1){//若当前位是1
                    res*=base;
                }
                base*=base;
                n=n>>1;//右移一位
            }
            return res;
      }
    }
    

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

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

    因为相对位置不变,所以需要稳定,都需要遍历。


    1.暴力解法:

    /**
    *  分别统计奇数偶数的数量,然后用两个数组存储,最后再放回原数组。
    */
    public class Solution {
        public void reOrderArray(int [] array) {
            int jCount=0;
            int oCount=0;
            for(int i=0;i<array.length;i++){
                if((array[i] & 1)==0){
                    //偶数
                    oCount++;
                }else{//奇数
                    jCount++;
                }
            }
            int jArr[]=new int[jCount];
            int oArr[]=new int[oCount];
            jCount=0;
            oCount=0;
            for(int i=0;i<array.length;i++){
                if ((array[i] & 1)== 1){
                    jArr[jCount]=array[i];
                    jCount++;
                }else{
                    oArr[oCount]=array[i];
                    oCount++;
                }
            }
            for(int i=0;i<jArr.length;i++){
                array[i]=jArr[i];
            }
            for(int i=0;i<oArr.length;i++){
                array[i+jArr.length]=oArr[i];
            }
        }
    }
    

    2.插入排序思想:

    public class Solution {
        public void reOrderArray(int [] array) {
            //相对位置不变,稳定性
            //插入排序的思想
            int m = array.length;
            int k = 0;//记录已经摆好位置的奇数的个数;也可以看作下一个奇数的下标
            for (int i = 0; i < m; i++) {
                if ((array[i] & 1) == 1) {//若为奇数
                    int j = i;//当前奇数所处位置
                    while (j > k) {//j >= k+1 此处将该奇数移到最前面奇数之后
                        int tmp = array[j];
                        array[j] = array[j-1];
                        array[j-1] = tmp;
                        j--;
                    }
                    k++;
                }
            }
        }
    }
    

    15.链表中倒数第k个结点

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

    双指针

    public class Solution {
        public ListNode FindKthToTail(ListNode head,int k) {
            //双指针  快指针比慢指针多走k-1步,当快指针到达末尾时,慢指针在倒数k结点
            if(k<=0)
                return null;
            if(head==null)
                return null;
            if(head.next==null)
                return head;
    
            ListNode slow=head;
            ListNode fast=head;
            int step=0;
            while(fast.next!=null){
                if(step<k-1){//当fast没走完k-1步时,只有fast走
                    step++;
                    fast=fast.next;
                }else{//当fast先走完k-1步时,slow也开始走
                    slow=slow.next;
                    fast=fast.next;
                }
                /*
                if(step>=k-1){
                    slow=slow.next;
                }
                step++;
                fast=fast.next;
                */
            }//当fast走到末尾,slow也走到了倒数第k个结点
            if(step<k-1)//证明k>链表长度
                return null;
            return slow;
        }
    }
    

    如有错误,欢迎指正

  • 相关阅读:
    剑指offer5-用两个栈实现队列
    剑指offer4-重建二叉树
    剑指offer3-从尾到头打印链表
    MATLAB曲线拟合函数
    贪心算法训练(九)——Best Cow Line(字典序最小问题)
    贪心算法训练(八)——智力大冲浪(带期限和罚款的单位时间调度问题)
    贪心算法训练(七)——加工生产调度(流水作业调度问题)
    贪心算法训练(六)——喷水装置(区间覆盖问题)
    贪心算法训练(五)——种树(区间选点问题)
    贪心算法训练(四)——(HDU1050)Moving Tables
  • 原文地址:https://www.cnblogs.com/lfz1211/p/12684509.html
Copyright © 2020-2023  润新知