zoukankan      html  css  js  c++  java
  • 剑指offer(二)

    概述

      继续刷题。。。

    第九题

    一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

     解题思路

    这道题的名字叫做变态跳台阶问题,那为什么叫变态我就不知道了,其实和第8题思路差不多。

    • 假设第一次青蛙跳1级,那剩余n-1级,也就是还有f(n-1)种跳法
    • 假设第一次青蛙跳2级,那剩余n-2级,也就是还有f(n-2)种跳法
    • ...
    • 假设第一次青蛙跳n级,那剩余n-n级
    • 总结下来就是 f(n) = f(n-1) + f(n-2) + f(n-3) +...+ f(0)
    • 由于f(0) = 1,f(1) = 1,f(2) = 2f(1),f(3) = 2f(2),所以f(n) = 2f(n-1) = 2(n-1)

    代码实现

    public class Solution {
        public int JumpFloorII(int target) {
            if(target <= 0){
                return 0;
            }
            return (int)Math.pow(2,target-1);
        }
    }

    第十题

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

    解题思路

    这道题叫做矩形覆盖问题,其实和第7题,第8题,第9题差不多,这道题也是使用斐波那契数列解决

    • 由于直接考虑整个矩形覆盖无从下手,那就考虑刚开始的地方,如果第一个2*1的小矩形竖着放(也就是还是2*1),那大矩形剩余2*(n-1),那就还有f(n-1)种覆盖方法
    • 如果第一个小矩形横着放(也就变成1*2),那这个小矩形下面的空间只能再横着放一个小矩形,那大矩形剩余2*(n-2),也就还有f(n-2)种覆盖方法
    • 综上所述,f(n) = f(n-1) + f(n-2)

    代码实现

    public class Solution {
        public int RectCover(int target) {
            if(target <= 0){
                return 0;
            }
            if(target == 1){
                return 1;
            }
            if(target == 2){
                return 2;
            }
              
            int a = 1;
            int b = 2;
            int c = 0;
            for(int i = 3;i <= target;i++){
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }

    第十一题

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

    解题思路

      这个题如果不仔细思考很简单,如果仔细思考,就比较复杂了,比如题中说的是一个整数,那这个整数是int类型,还是long类型的,虽然牛客网上代码限定是int类型,因为int类型无论是32位编译器还是64位编译器都是占用4位,也就是32个字节,如果是这样,那就简单了,因为负数在计算机中本身就是使用补码存储的,所以可以使用如下方式解决。

    代码

    直接获取整数的二进制表示,统计一下1的个数,我并不喜欢这种解决方式(这种时间复杂度是O(n))

    public class Solution {
        public int NumberOf1(int n) {
            int t=0;
                char[]ch=Integer.toBinaryString(n).toCharArray();
                for(int i=0;i<ch.length;i++){
                    if(ch[i]=='1'){
                        t++;
                    }
                }
                return t;
        }
    }

    还有一种就是通过位运算来统计,时间复杂度为O(m),其中m为1的个数

    public class Solution {
        public int NumberOf1(int n) {
            int count = 0;
            while(n!= 0){
                count++;
                n = n & (n - 1);
             }
            return count;
        }
    }

    由于我在第一次做这个题的时候,并不知道怎么获取计算机中整数二进制表示,而且没有想到使用位运算,想了一种非常复杂的方法,先贴在这里,方便以后看

    import java.util.Stack;
    public class Solution {
        public int NumberOf1(int n) {
            if (n == 0){
                return 0;
            }
            int bark = n;
            n = Math.abs(n);
            Stack<Integer> stack = new Stack();
            while(n != 0){
                int result = n % 2;
                if(result == 0){
                    stack.push(0);
                    n = n/2;
                }else{
                    stack.push(1);
                    n = (n - result)/2;
                }
            }
            
            int result = 0;
            int count = 0;
            if (bark > 0){
                while(!stack.isEmpty()){
                    result = (int)stack.pop();
                    if(result == 1){
                        count++;
                    }
                }
            }else{
                int[] array = new int[32];
                int length = stack.size();
                 for(int i=0;i<array.length;i++){
                    if(array.length - i == stack.size()){
                        result = (int)stack.pop();
                        if(result == 1){
                        array[i] = 0;
                        }else{
                            array[i] = 1;
                        }
                    }else{
                        array[i]=1;
                    }
                }
                for(int i=array.length-1;i>=0;i--){
                    if(array[i]==0){
                        array[i] = 1;
                        break;
                    }else{
                        array[i]=0;
                        if(i-1<0){
                            return -1;
                        }else{
                            if(array[i-1] == 0){
                                array[i-1] = 1;
                                break;
                            }
                        }
                    }
                }
                for(int i=0;i<array.length;i++){
                    if(array[i]==1){
                        count++;
                    }
                }
            }
            return count;
        }
    }
    View Code

    第十二题

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

    解题思路

    这道题,咋一看很简单,直接写个for循环,或者使用系统自带的函数都可以轻松解决,但是这个题并不是看你能不能把结果搞出来,而是看你怎么搞。

    如果直接使用for循环,时间复杂度为O(n),比如计算38,需要8次计算,那有没有比这个次数更少的方法呢?答案是有的,就是快速求幂算法,下面简单介绍一下这个算法。

    如果计算38,我们肯定要计算3*3,这是32,那其实38 = (34 * 34) = (3 * 32) * (3 * 32),所以最后我们只需要计算3次,第一次计算3*3=3,第二次计算3 * 3= 34,第三次计算34 * 34 = 38

    好有了上面的基础,我们就可以正式来解决我们的问题,我们发现8的8位二进制表示为:0000 1000,我们发现其实二进制中1的位置右边3个0,正好是要计算的3次,(这里表述有问题,大家酬和着看,意思就是这个意思)

    代码

    直接计算结果的方法(简单又粗暴)

    public class Solution {
        public double Power(double base, int exponent) {
            return Math.pow(base,exponent);
      }
    }

    使用快速幂运算

       def fast_power(self, base, exponent):
            if base == 0:
                return 0
            if exponent == 0:
                return 1
            e = abs(exponent)
            tmp = base
            res = 1
            while(e > 0):
                #如果最后一位为1,那么给res乘上这一位的结果
                if (e & 1 == 1):
                    res =res * tmp
                e = e >> 1
                tmp = tmp * tmp
            return res if exponent > 0 else 1/res

    第十三题

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

    解题思路

      这个题我想的思路很简单,直接把奇数和偶数先找出来分别存放,之后再合并到一起。

    代码

    public class Solution {
        public void reOrderArray(int [] array) {
            int[] a = new int[array.length];
            int[] b = new int[array.length];
            
            int j = 0;
            int k = 0;
            for(int i = 0;i<array.length;i++){
                if(array[i] % 2 == 1){
                    a[j] = array[i];
                    j++;
                }else{
                    b[k] = array[i];
                    k++;
                }
            }
            System.arraycopy(a,0,array,0,j);
            System.arraycopy(b,0,array,j,k);
    
        }
    }

    第十四题

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

    解题思路

    这个题按照常规的思考方式来,就是先遍历一遍,记录一下总数,之后再去遍历找到倒数第k个,这个时间复杂度是很高的,有一种更好的解决办法,使用快慢指针解决,具体就是第一个指针先走,当走到第K个节点的时候,第二个指针开始走,当第一个指针走到结尾的时候,第二个指针指向的就是倒数第k个节点

    代码

    public class Solution {
        public ListNode FindKthToTail(ListNode head,int k) {
            ListNode p = head;
            int i;
            for(i = 0;head != null;i++){
                if(i > k-1){
                    p = p.next;
                }
                head = head.next;
            }
            if(i < k){
                return null;
            }
            return p;
        }
    }

    第十五题

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

    解题思路

    这个题很简单,就是遍历的时候修改一下指针的方向就可以了,可能出问题的地方就是要搞清楚每个变量到底是指向哪个节点,不要两个变量指向同一个节点,一个变量把这个节点修改了,那另一个变量自然也就跟着变了。

    代码

    public class Solution {
        public ListNode ReverseList(ListNode head) {
            if(head == null){
                return null;
            }
            ListNode temp = new ListNode(head.val);
            while(head.next != null){
                ListNode temp1 = new ListNode(head.next.val);
                temp1.next = temp;
                temp = temp1;
                head = head.next;
            }
            return temp;
        }
    }

    第十六题

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

    解题思路

    这个题和上一个题差不太多,就是遍历两个链表,然后逐个比较大小,最后构建一个新的链表

    代码

    /*
    public class ListNode {
        int val;
        ListNode next = null;
    
        ListNode(int val) {
            this.val = val;
        }
    }*/
    public class Solution {
        public ListNode Merge(ListNode list1,ListNode list2) {
            if(list1 == null){
                return list2;
            }
            if(list2 == null){
                return list1;
            }
            if(list1 == null && list2 == null){
                return null;
            }
            
            ListNode next1;
            ListNode next2;
            ListNode next = null;
            if(list1.val < list2.val){
                next = list1;
                list1 = list1.next;
            }else{
                next = list2;
                list2 = list2.next;
            }
            ListNode temp = next;
            while(list1 != null && list2 != null){
                if(list1.val >= list2.val){
                    next2 = list2.next;
                    temp.next = list2;
                    temp = temp.next;
                    list2 = next2;
                }else{
                    next1 = list1.next;
                    temp.next = list1;
                    temp = temp.next;
                    list1 = next1;
                }
            }
            if(list1 != null){
                temp.next = list1;
            }
            if(list2 != null){
                temp.next = list2;
            }
            return next;
        }
    }

    写在最后的话

      最近股市上涨,我也跟风买,谁知买在了高点,每天心心念念想着盯盘,为了百分之几的利润高兴或者难过,今天全部清仓,赔了10几个点,反而变得清净了,果然是人若没有执着,没有贪,没有嗔,没有痴,就会变得平静,就会有定。  

  • 相关阅读:
    java环境变量配置 win7/win8 java配置
    (JSON转换)String与JSONObject、JSONArray、JAVA对象和List 的相互转换
    (yum)更新yum报错:yum makecache: error: argument timer: invalid choice: 'fast' (choose from 'timer')
    (ElasticSearch)中文字符串精确搜索 term 搜不到结果
    (端口)打开阿里云服务组端口和防火墙端口
    (乱码)Spring Boot配置文件出现乱码解决方案
    (特殊字符)url中包含特殊字符导致请求报错的解决方案
    (端口占用)Windows 查看所有端口和PID
    (注释)IDEA快捷键注释不能自动对齐
    (JDK)oracle下载jdk需要注册?
  • 原文地址:https://www.cnblogs.com/gunduzi/p/13321565.html
Copyright © 2011-2022 走看看