变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题思路:比如5层台阶的跳法,
- 从第4层跳到5层,加上之前第1层到第4层的解法
- 从第3层跳到5层,加上之前第1层到第3层的解法
- …
- 从第1层跳到5层
public class Solution {
public int JumpFloorII(int target) {
int memo[] = new int[target+1];
memo[0] = 1;
memo[1] = 1;
for(int i = 2; i <= target; ++i){
for(int j = 0; j <= i; ++j){
memo[i] = memo[i] + memo[i-j];
}
}
return memo[target];
}
}
丑数
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
解题思路:对于每个丑数,它都要乘以2,3和5,然后形成新的丑数
public class Solution {
private int min_3(int x, int y, int z){
return Math.min(x, Math.min(y, z));
}
public int GetUglyNumber_Solution(int index) {
if(index == 0){
return 0;
}
int []memo = new int[index+1];
memo[0] = 1;
int a = 0;
int b = 0;
int c = 0;
for(int i = 1; i <= index; ++i){
memo[i] = min_3(memo[a]*2, memo[b]*3, memo[c]*5);
if(memo[i] == memo[a]*2){
++a;
}
if(memo[i] == memo[b]*3){
++b;
}
if(memo[i] == memo[c]*5){
++c;
}
}
return memo[index-1];
}
}
全排列
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba
解题思路:
- 使用visited数组进行记忆搜索,确保每个字符访问过一次
- 对char数组进行排序,是确保每个重复的字符,在每次递归只使用一次
import java.util.*;
public class Solution {
private ArrayList<String> A;
private boolean []visited;
public void tryPermutation(char []chars, String s){
if(s.length() == chars.length){
A.add(s);
return;
}
for(int i = 0; i < chars.length; ++i){
if(i != 0 && chars[i-1] == chars[i] && visited[i-1]){
continue;
}
if(!visited[i]){
visited[i] = true;
s += chars[i];
tryPermutation(chars, s);
s = s.substring(0, s.length()-1);
visited[i] = false;
}
}
}
public ArrayList<String> Permutation(String str) {
A = new ArrayList<String>();
if(str.length() == 0){
return A;
}
visited = new boolean[str.length()];
char []chars = str.toCharArray();
Arrays.sort(chars);
tryPermutation(chars, "");
return A;
}
}
二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
解题思路:二进制位中,每次n减1,其对应的最高位会置0;并且(n-1)&n不影响其二进制中低位中的1。
public class Solution {
public int NumberOf1(int n) {
int cnt = 0;
while(n != 0){
++cnt;
n = (n-1) & n;
}
return cnt;
}
}
旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解题思路:二分搜索
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int lo = 0;
int hi = array.length - 1;
while(lo <= hi){
int mid = lo + (hi - lo) / 2;
if(array[mid] == array[hi]){
hi -= 1;
}
else if(array[mid] < array[hi]){
hi = mid;
}
else if(array[mid] > array[hi]){
lo = mid+1;
}
}
return array[lo];
}
}
滑动窗口的最大值
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
解题思路:一个列队,保存窗口期内最大值的下标。
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size){
ArrayList<Integer> res = new ArrayList<>();
LinkedList<Integer> maxIndex = new LinkedList<>();
if(size <= 0){
return res;
}
for(int i = 0; i < num.length; ++i){
while(!maxIndex.isEmpty() && num[i] >= num[maxIndex.getLast()]){
maxIndex.removeLast();
}
maxIndex.addLast(i);
if(i + 1 >= size){
res.add(num[maxIndex.getFirst()]);
}
if(i - size + 1 >= maxIndex.getFirst()){
maxIndex.removeFirst();
}
}
return res;
}
}
栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
解题思路:
- 新建一个栈,模拟数据的压入和弹出
- 栈中未弹出的数据,与popA进行比较
- 判断数据有残留的数据
import java.util.*;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
Stack<Integer> stack = new Stack<Integer>();
int cursor = 0;
for(int i = 0; i < pushA.length; ++i){
stack.push(pushA[i]);
while(!stack.isEmpty() && stack.peek() == popA[cursor]){
stack.pop();
++cursor;
}
}
for(int i = cursor; i < popA.length; ++i){
if(!stack.isEmpty() && stack.peek() == popA[i]){
stack.pop();
}
}
return stack.isEmpty();
}
}
数值的整数次方
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
解题思路:分治
public class Solution {
private double tryPower(double base, int p){
if(p == 0){
return 1.0;
}
if(p == 1){
return base;
}
double ans = 0;
if(p % 2 == 0){
ans = tryPower(base, p/2) * tryPower(base, p/2);
}
else{
ans = base * tryPower(base, p/2) * tryPower(base, p/2);
}
return ans;
}
public double Power(double base, int exponent) {
if(exponent < 0){
return 1 / tryPower(base, exponent);
}
else{
return tryPower(base, exponent);
}
}
}
解题思路:简单快速幂
举个例子,
2的5次方,指数5的二进制为101,那么2的5次方为(2*2*2*2) * (1) * (2)
同理可得,
n的5次方为,(n*n*n*n) * (1) * (n)
n的9(1001)次方为, (n*n*n*n*n*n*n*n)*(1)*(1)*(n)
public class Solution {
public double Power(double base, int exponent) {
int p = Math.abs(exponent);
double ans = 1.0;
while(p != 0){
if((p & 1) == 1){
ans *= base;
}
base *= base;
p >>= 1;
}
return exponent < 0 ? 1.0/ans : ans;
}
}