跳台阶问题
问题描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
测试用例
输入:3
返回值:4
解决思路
转换为数学问题:
AC
java
public class Solution {
public int jumpFloorII(int target) {
//f(1)=1,f(n)=pow(2,n-1)
return target <= 0 ? 0 : 1 << (target - 1);
}
}
python
# -*- coding:utf-8 -*-
class Solution:
def jumpFloorII(self, number):
# write code here
return number if number<=1 else pow(2, number-1)
生成格雷码
问题描述
在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同, 则称这种编码为格雷码(Gray Code),请编写一个函数,使用递归的方法生成N位的格雷码。
给定一个整数n,请返回n位的格雷码,顺序为从0开始。
测试用例
输入:1
返回:["0","1"]
解决思路
递归实现:
首先可以看出,n位有2^n个格雷码;
递归结束条件,n=1时,返回的是[‘0’,‘1’];
返回上一次,在n=2时,在n=1的基础上,每个结果上面分别加上0和1,构成n=2的结果;
由此可见,本次的结果,都是上一次结果的基础上,每个结果首位加0和1;
AC
java
import java.util.*;
public class GrayCode {
public String[] getGray(int n) {
// write code here
String[] fr = new String[(int) Math.pow(2,n)];
if(n==1){
fr[0]="0";
fr[1]="1";
return fr;
}
fr = getGray(n-1);
String[] res = new String[2*fr.length];
for (int i = 0; i < fr.length; i++) {
res[i]="0"+fr[i];
res[fr.length+i]="1"+fr[fr.length-1-i];
}
return res;
}
}
python
class GrayCode:
def getGray(self, n):
if n==1:
return ['0','1']
res = self.getGray(n-1)
fr = []
len_res = len(res)
for i in res:
fr.append('0'+i)
#这里注意倒序,因为要保证相邻两位代码,只有1位不相同
for i in range(len_res-1,-1,-1):
fr.append('1'+res[i])
return fr
微信红包
问题描述
春节期间小明使用微信收到很多个红包,非常开心。在查看领取红包记录时发现,某个红包金额出现的次数超过了红包总数的一半。请帮小明找到该红包金额。写出具体算法思路和代码实现,要求算法尽可能高效。
给定一个红包的金额数组gifts及它的大小n,请返回所求红包的金额。
若没有金额超过总数的一半,返回0。
测试用例
输入:[1,2,3,2,2],5
返回:2
解决思路
利用map数据结构进行操作,key的value超过一半,就return key;
AC
java
import java.util.*;
public class Gift {
public int getValue(int[] gifts, int n) {
// write code here
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int x:gifts) {
if(map.containsKey(x)){
map.put(x,map.get(x)+1);
if(map.get(x)>(n/2)){
return x;
}
}else{
map.put(x,1);
}
}
return 0;
}
}
python
class Gift:
def getValue(self, gifts, n):
# write code here
dic= dict()
for i in gifts:
if i in dic.keys():
dic[i] += 1
if dic[i]>n/2:
return i
else:
dic[i]=1
return 0
子集
问题描述
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集
测试用例
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
解决思路
AC
python
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res,path=[],[]
self.dfs(nums,0,res,path)
return res
def dfs(self,nums,index,res,path):
#一个path就是一个解
res.append(copy.deepcopy(path))
for i in range(index,len(nums)):
path.append(nums[i])
self.dfs(nums,i+1,res,path)
path.pop()
子集2
问题描述
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
测试用例
示例 1:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
解决思路
回溯法类似,与之前的区别在于存在重复整数,需要先对原数组进行排序,然后再开始回溯;
AC
java
public List<List<Integer>> res = new ArrayList<List<Integer>>();
public List<Integer> t = new ArrayList<Integer>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
dfs(nums,0);
return res;
}
public void dfs(int[] nums,int index){
if (index==nums.length){
res.add(new ArrayList<Integer>(t));
return;
}
if (!res.contains(t)){
res.add(new ArrayList<Integer>(t));
}
for (int i = index; i < nums.length; i++) {
if (i>index&&(nums[i]==nums[i-1])){
continue;
}
t.add(nums[i]);
dfs(nums,i+1);
t.remove(t.size()-1);
}
}
python
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
res,path=[],[]
nums.sort()
self.dfs(nums,0,res,path)
return res
def dfs(self,nums,index,res,path):
if path not in res:
res.append(path)
for i in range(index, len(nums)):
if i > index and nums[i] == nums[i - 1]:
continue
self.dfs(nums, i + 1, res, path + [nums[i]])
最长公共子序列
问题描述
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
测试用例
示例 1:
输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。
示例 2:
输入:text1 = “abc”, text2 = “abc”
输出:3
解释:最长公共子序列是 “abc” ,它的长度为 3 。
示例 3:
输入:text1 = “abc”, text2 = “def”
输出:0
解释:两个字符串没有公共子序列,返回 0 。
提示:
1 <= text1.length, text2.length <= 1000
text1 和 text2 仅由小写英文字符组成。
解决思路
**动态规划题目:**典型二维动态规划问题;
text1的长度为m,text2的长度为n,创建m+1行,n+1列的二维数组dp,其中的dp[i] [j]表示text1[0:i]和text2[0:j]的最长公共子序列的长度
动态规划的边界情况:
当 i=0i=0 时,text 1 [0:i] 为空,空字符串和任何字符串的最长公共子序列的长度都是 0,因此对任意 j,有dp[0] [j] =0;
当 j=0j=0 时,text 2 [0:j] 为空,同理可得,对任意i,有 dp[i] [0] = 0。
因此动态规划的边界情况是:当 i=0 或 j=0 时,dp[i] [j]=0。
AC
java
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
int [][] dp = new int[m+1][n+1];
for (int i = 1; i <=m ; i++) {
for (int j = 1; j <=n ; j++) {
if (text1.charAt(i-1)==text2.charAt(j-1)){
//更新状态方程
dp[i][j] = dp[i-1][j-1]+1;
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[m][n];
}
}
全排列
问题描述
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
测试用例
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
解决思路
回溯法:到底的每条路径即为一种可能的排列,可以结合树来思考问题,找出循环以及结束的调价;
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
AC
python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def dfs(num,li,depth,unsigned,path):
if depth==num:
nonlocal res
res.append(copy.deepcopy(path))
for i in range(num):
if unsigned[i]!=0:
continue
path.append(li[i])
unsigned[i]=1
dfs(num,li,depth+1,unsigned,path)
path.remove(li[i])
unsigned[i]=0
used = [0]*len(nums)
dfs(len(nums),nums,0,used,[])
return res
最长递增子序列
问题描述
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
测试用例
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
解决思路
动态规划:定义状态,找出状态转化方程,状态初始化;
定义dp[n]数字,状态dp[i]表示到num[i]为止,最长上升子序列的长度;
dp[i] = max(dp[j])+1,0<j<i,并且保证组成上升子序列num[i]>num[j];
最后所求结果为dp[]数组的最大值;
AC
python
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if not nums:
return 0
dp = [1]*len(nums)
for i in range(len(nums)):
for j in range(i):
if nums[i]>nums[j]:
dp[i] = max(dp[i],dp[j]+1)
return max(dp)