小白的LeetCode日记记录Day2

6.斐波那契数列

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

解法一:递归。教科书级解法ε=(´ο`*)))但是在递归的过程中会产生很多重复的数,这种方法会产生重复计算浪费时间。不建议



但是!可以对递归进行改良!!利用map的key值唯一特性来储存数据,每当计算完数据放进map前先进行判断,如果重复了就直接从map中取,不重复就把值放进去,这样计算时就节省了很多时间( * ^ ▽^*)

int constant = 1000000007;

public int fib(int n) {
     
    return fib(n, new HashMap());
}

public int fib(int n, Map<Integer, Integer> map) {
     
    if (n < 2)
        return n;
    if (map.containsKey(n))
        return map.get(n);
    int first = fib(n - 1, map) % constant;
    map.put(n - 1, first);
    int second = fib(n - 2, map) % constant;
    map.put(n - 2, second);
    int res = (first + second) % constant;
    map.put(n, res);
    return res;
}

解法二:用循环数组来做。设斐波那契值为a,b,每次计算和之后将b的值赋给a,并将计算后的和赋值给b。这样就节省了很多空间时间啦

class Solution {
     
    public int fib(int n) {
     
        if(n==0)
            return 0;
        if(n==1)
            return 1;
        else{
     int fibMinusOne = 0;
        int fibMinusTwo = 1;
        int fibN = 0;
        for(int i=2;i<=n;i++){
     
            fibN = (fibMinusOne + fibMinusTwo)%1000000007;
            fibMinusOne = fibMinusTwo;
            fibMinusTwo = fibN;
        }
        return fibN;
        }
    }
}

7.青蛙跳台阶

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

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

解法:首先先分类讨论,当呱呱面前没有或者有一级台阶时它可以跳一下,有两级台阶时它可以选择跳一下或者跳两下。当它选择跳一级台阶时,剩下的台阶就剩下n-1级,选择跳两级台阶时就剩下n-2级,这样可以总结出一个数学公式:
f(n) = f(n-1)+f(n-2)-------------Σ(⊙▽⊙"a
好眼熟,这不就是斐波那契数列,于是…

class Solution {
     
    public int numWays(int n) {
     
        if(n==0)
            return 1;
        if(n==1||n==2)
            return n;
        int jump1 = 1;
        int jump2 = 2;
        int jump = 0;
        for(int i = 3;i<=n;i++){
     
            jump = (jump1 + jump2)%1000000007;
            jump1 = jump2;
            jump2 = jump;
        }
    return jump;    
    }
}

8.旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

解法:运用二分查找。因为整个数组是一个递增的缘故,我们从数组中间开始找起。如果中间这个数比最后那个数大,说明中间这个数是属于前半部分的,那么我们需要往后开始找,所以起点就变为中间数+1;如果中间这个数比最后那个数小,说明中间这个数在数组的后半部分,需要我们从前面开始找,那么我们的终点就是中间数;当然还有一种极端情况就是中间的数和最后的数相等,这个时候我们就只能把终点往前推一个。在经过排序之后我们就能找到最小的那个数,也就是numbers[low]

class Solution {
     
    public int minArray(int[] numbers) {
     
        int low = 0;
        int high = numbers.length-1;
        while(low<high){
     
            int mid = low + (high - low)/2;
            if(numbers[mid]<numbers[high]){
     
                high = mid;
            }else if(numbers[mid]>numbers[high]){
     
                low = mid + 1;
            }else{
     
                high--;
            }
        }
        return numbers[low];
    }
}

9.二进制中一的个数

请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

解法一:与1位运算。与1位运算会使二进制下的n个位与1进行与逻辑判断,当个位为1就输出1。准备一个计数器,当它不为0时,将n与1做位运算并且将结果赋值给计数器,之后将n位数右移一位(右移:>>>=)最后返回计数器的值

public class Solution {
     
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
     
        int count = 0;
        while(n!=0){
     
            count+=n&1;
            n>>>=1;
        }
        return count;
    }
}

解法二:将n与n-1做位运算,这种方法会使n的1后面的0都变成1。当n不为0时,把n与n-1与的结果赋给n,并且计数器+1。

public class Solution {
     
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
     
        int count = 0;
        while(n!=0){
     
            n=n&(n-1);
            count++;
        }
        return count;
    }
}

10.打印从 1 到最大的 n 位数

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

解法一:通常做法就是求出n位数的最大值,然后逐个打印,但是此方法在遇到大数(超过int类型能表示的数)就会不能正确表示

class Solution {
     
    public int[] printNumbers(int n) {
     
        int sum = (int)Math.pow(10,n)-1;
        int num[] = new int[sum];
        for(int i=0;i<sum;i++){
     
            num[i] = i+1;
        } 
    return num;
    }    
}

解法二:考虑到大数越界的问题,由于每种类型都有限定范围,所以选用字符串来表示数字,运用循环+递归的形式

class Solution {
     
    int[] res;
    int nine = 0, count = 0, start, n;
    char[] num, loop = {
     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    public int[] printNumbers(int n) {
     
        this.n = n;
        res = new int[(int)Math.pow(10, n) - 1];
        num = new char[n];
        start = n - 1;
        dfs(0);
        return res;
    }
    void dfs(int x) {
     
        if(x == n) {
     
            String s = String.valueOf(num).substring(start);
            if(!s.equals("0")) res[count++] = Integer.parseInt(s);
            if(n - start == nine) start--;
            return;
        }
        for(char i : loop) {
     
            if(i == '9') nine++;
            num[x] = i;
            dfs(x + 1);
        }
        nine--;
    }
}

你可能感兴趣的:(数据结构与算法)