第二十三天
1414 和为K的最少斐波那契数字数目
给你数字k
,请你返回和为k
的斐波那契数字的最少数目,其中,每个斐波那契数字都可以被使用多次。
斐波那契数字定义为:
- F1 = 1
- F2 = 1
- Fn = Fn-1 + Fn-2 , 其中 n > 2 。
数据保证对于给定的 k
,一定能找到可行解。
方法 贪心
由于所给的k
一定能够表示成几个斐波那契数的和,依据斐波那契数列的性质,我们假设
K=f1+f2+f3+...fn
K=f_1+f_2+f_3+...f_n
K=f1+f2+f3+...fn
是所求的最少的斐波那契数的和。并且f
按照降序排列。现在考虑f
应当取何值,才能让整体的数量最少。一种很容易考虑到的方法是让每个f
都尽可能的靠近K
,这样能够使得数量最少,为什么这是对的?
如果我们选取了某个f2
,它的值低于我们贪心的f1
,由斐波那契数列的性质可以直到,一定存在另外一个数f3
,使得f1=f2+f3
,这样一来,如果我们选取了f2
,会造成总的数量增加1
。
class Solution {
public int findMinFibonacciNumbers(int k) {
int[] fibNum = new int[]{1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170};
int n = fibNum.length;
int res = 0;
while (k > 0){
int index = 0;
while (fibNum[index] <= k) index++;
k -= fibNum[index - 1];
res++;
}
return res;
}
}
78 子集
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
方法 回溯
回溯问题的基本解决思路,属于模板题。
class Solution {
List<List<Integer>> res;
ArrayList<Integer> subSet;
public List<List<Integer>> subsets(int[] nums) {
res = new ArrayList<>();
subSet = new ArrayList<>();
getSubSet(nums, 0);
return res;
}
public void getSubSet(int[] nums, int depth){
if (depth == nums.length){
res.add(new ArrayList<>(subSet));
return;
}
subSet.add(nums[depth]);//选取第depth位置的数
getSubSet(nums, depth + 1);
subSet.remove(subSet.size() - 1);//不选第depth位置的数
getSubSet(nums, depth + 1);
}
}
90 子集Ⅱ
给你一个整数数组nums
,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
方法 哈希+回溯
定义一个哈希函数唯一确定一个子集中的元素(只和数量和值有关,和顺序无关),使用HashSet
保存每一个唯一的子集的hash
值,如果发现相同,则不加入到结果中去。
class Solution {
List<List<Integer>> res;
ArrayList<Integer> subSet;
Set<Long> set;
boolean f;
public List<List<Integer>> subsetsWithDup(int[] nums) {
res = new ArrayList<>();
subSet = new ArrayList<>();
set = new HashSet<>();
for (int i : nums) set.add((long)i);
f = set.size() == nums.length;
set.clear();
getSubSet(nums, 0);
return res;
}
public long getHash(ArrayList<Integer> arrayList){
long res = 1;
for (int i : arrayList){
if (i == 0) res -= 1315;
else if (i == 1) res *= 11564;
else if (i == -1) res += -1577;
else res *= (5 * i * i);
}
return res;
}
public void getSubSet(int[] nums, int depth){
if (depth == nums.length){
if (!set.contains(getHash(subSet)) || f){
set.add(getHash(subSet));
res.add(new ArrayList<>(subSet));
}
return;
}
subSet.add(nums[depth]);
getSubSet(nums, depth + 1);
subSet.remove(subSet.size() - 1);
getSubSet(nums, depth + 1);
}
}