写一个函数,输入 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;
}
}
}
一只青蛙一次可以跳上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;
}
}
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [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];
}
}
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 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;
}
}
输入数字 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--;
}
}