这里写目录标题
剪绳子
思路:1.尽可能剪成长度为3的长度,其次是为2的长度
最优: 3 。把绳子尽可能切为多个长度为 33 的片段,留下的最后一段绳子的长度可能为 0,1,2 三种情况。
次优: 2 。若最后一段绳子长度为 2 ;则保留,不再拆为 1+1 。
最差: 1 。若最后一段绳子长度为 1 ;则应把一份 3 +1 替换为 2 + 2
2.动态规划,dp[i]表示长度为 i 时的最大长度。
3.贪心,尽可能剪成长度为3的长度
public class Solution {
public int cutRope(int target) {
if(target <= 3) return target - 1;
if(target % 3 == 0){
return (int)Math.pow(3, target / 3);
}else if(target % 3 == 1){
return 4 * (int)Math.pow(3, target / 3 - 1);
}else{
return 2 * (int)Math.pow(3, target / 3);
}
}
}
根据转移方程反推初始条件 dp[5] = dp[2] * dp[3] = 6,所以dp[2] = 2, dp[3] = 3;
public class Solution {
public int cutRope(int n) {
if(n < 2) return 0;
// 长度为3时,返回2
if(n <= 3) return n - 1;
int[] dp = new int[n + 1];
dp[2] = 2;
dp[3] = 3;
for(int i = 4; i <= n; i++){
for(int j = 2; j <= i / 2; j++){
// dp[i] = dp[i] >= dp[j] * dp[i - j] ? dp[i] : dp[j] * dp[i - j];
dp[i] = Math.max(dp[i], dp[j] * dp[i - j]);
}
}
return dp[n];
}
}
while循环结束后,n只有1,2,3,4四种情况,直接返回 n * res
public class Solution {
public int cutRope(int n) {
if(n <= 3) return n - 1;
int res = 1;
while(n > 4){
res *= 3;
n -= 3;
}
return n * res;
}
}
二维数组查找
1.从左下角或者右上角开始查找
public class Solution {
public boolean Find(int target, int [][] array) {
if(array.length == 0 || array[0].length == 0) return false;
int i = array.length - 1, j = 0;
while(i >= 0 && j < array[0].length){
if(array[i][j] == target){
return true;
}else if(target > array[i][j]){
j++;
}else{
i--;
}
}
return false;
}
}
2.二分法查找,将二维数组“摊平”成一维数组matrix[mid_idx / n][mid_idx % n]
public class Solution {
public boolean Find(int target, int [][] matrix) {
int m = matrix.length;
if (m==0) return false;
int n = matrix[0].length;
// 确定二分法左右序号
int left = 0, right = n * m - 1;
int mid_idx, mid_element;
while (left <= right){
mid_idx = (left + right) / 2;
mid_element = matrix[mid_idx / n][mid_idx % n];
if (target == mid_element) return true;
else {
if (target > mid_element) left = mid_idx + 1;
else right = mid_idx - 1;
}
}
return false;
}
}
滑动窗口最大值
- 暴力
- 单调队列:单调队列一般用于维护局部的单调性
边界条件:num.length == 0 || num.length < size || size == 0
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size) {
if(num.length == 0 || num.length < size || size == 0) return new ArrayList<>();
int k = num.length - size + 1;
ArrayList<Integer> res = new ArrayList<>();
for(int i = 0; i < k; i++){
int temp = num[i];
for(int j = i; j < i + size; j++){
temp = Math.max(temp, num[j]);
}
res.add(temp);
}
return res;
}
}
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size) {
ArrayList<Integer> res = new ArrayList<>();
if(num.length == 0 || size == 0 || num.length < size) return res;
Deque<Integer> queue = new LinkedList<>();
int k = num.length - size + 1;
// 还未形成窗口
for(int i = 0; i < size; i++){
// 如果单调队列的队尾小于要入队的元素nums[i]
if(!queue.isEmpty() && queue.peekLast() < num[i]){
queue.pollLast();
}
queue.offerLast(num[i]);
}
res.add(queue.peek());
// 形成窗口
for(int i = size; i < num.length; i++){
// 窗口滑动时,nums[i - k] 移出了窗口,如果移出了窗口的值nums[i - k]刚好是最大值,需将 deque 内的对应元素一起删除
if(queue.peek() == num[i - size]){
queue.pollFirst();
}
while(!queue.isEmpty() && queue.peekLast() < num[i]){
queue.pollLast();
}
queue.offerLast(num[i]);
res.add(queue.peek());
}
return res;
}
}
两个栈实现队列
思路:一个栈负责入队,一个栈负责出队。
注意:当出队的栈为空时,要把入队的栈全部出栈到出队的栈。
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
// 如果栈为空,将栈1的元素全部弹出后压如
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
// 栈不为空,直接返回栈顶
}else{
return stack2.pop();
}
}
}
第一次出现的字符
思路:哈希+遍历
public class Solution {
//Insert one char from stringstream
StringBuilder sb = new StringBuilder();
char[] count = new char[256];
public void Insert(char ch)
{
sb.append(ch);
count[ch]++;
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
for(int i = 0; i < sb.length(); i++){
if(count[sb.charAt(i)] == 1){
return sb.charAt(i);
}
}
return '#';
}
}
数组中重复的数字
思路:哈希
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型一维数组
* @return int整型
*/
public int duplicate (int[] numbers) {
// write code here
int n = numbers.length;
int[] count = new int[n];
for(int i = 0; i < n; i++){
if(numbers[i] < 0 || numbers[i] > n){
return -1;
}
count[numbers[i]]++;
}
for(int i = 0; i < n; i++){
if(count[i] > 1){
return i;
}
}
return -1;
}
}
数组中出现次数超过一半的数字
思路:1.哈希 2.摩尔投票
摩尔投票法:记录票数votes,众数res,遍历数组,如果num == res,票数+1,如果num != res,票数-1,当 票数 votes 等于 0 ,则假设当前数字 num 是众数;,最后验证这个数出现的次数是否超过一半。
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
HashMap<Integer, Integer> map = new HashMap<>();
int len = array.length;
for(int num : array){
map.put(num, map.getOrDefault(num, 0) + 1);
}
for(int key : map.keySet()){
if(map.get(key) > len / 2){
return key;
}
}
return 0;
}
}
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
int res = 0, votes = 0;
for(int num : array){
if(votes == 0) res = num;
votes += num == res ? 1 : -1;
}
int count = 0;
for(int num : array){
if(res == num){
count++;
}
}
// 判断出现次数是否超过一半
return count > array.length / 2 ? res : 0 ;
}
}
数组中只出现一次的两个数字
思路:1.哈希 2.位运算
位运算bitmask &= -bitmask,表示的是把bitmask二进制中最右边的1保留,其他位置全部变为0
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* @param array int整型一维数组
* @return int整型一维数组
*/
public int[] FindNumsAppearOnce (int[] array) {
// write code here
int[] res = new int[2];
Arrays.sort(array);
HashMap<Integer, Integer> map = new HashMap<>();
for(Integer num : array){
// if(map.containsKey(num)){
// map.put(num, map.get(num) + 1);
// }else{
// map.put(num, 1);
// }
map.put(num, map.getOrDefault(num, 0) + 1);
}
int index = 0;
for(Integer key : map.keySet()){
if(map.get(key) == 1){
res[index] = key;
index++;
}
}
return res;
}
}
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型一维数组
* @return int整型一维数组
*/
public int[] FindNumsAppearOnce (int[] array) {
// write code here
int[] res = new int[2];
int tmp = 0;
for(int num : array){
tmp ^= num;
}
// 得到第一位不是0的数
int mask = 1;
while((mask & tmp) == 0){
mask <<= 1;
}
// 也可以直接tmp &= -tmp;
// 分组
int a = 0, b = 0;
for(int arr : array){
if((mask & arr) == 0){
a ^= arr;
}else{
b ^= arr;
}
}
res[0] = a < b ? a : b;
res[1] = a < b ? b : a;
return res;
}
}
调整数组顺序
要求:奇数在偶数前面,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路:如果不考虑相对位置,可以直接使用双指针,但是现在需要考虑位置。
调整数组顺序
不考虑相对位置
class Solution {
public int[] exchange(int[] nums) {
int l = 0, r = nums.length - 1;
while(l < r){
if(nums[l] % 2 == 1){
l++;
continue;
}
if(nums[r] % 2 == 0){
r--;
continue;
}
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
}
return nums;
}
}
//slow指向奇数存放的位置
//fast碰到奇数时互换位置,碰到偶数时+1
//如果找到奇数则与slow指向的数进行交换
class Solution {
public int[] exchange(int[] nums) {
int slow = 0, fast = 0;
while(fast < nums.length){
if(nums[fast] % 2 == 1){
int temp = nums[fast];
nums[fast] = nums[slow];
nums[slow] = temp;
slow++;
}
fast++;
}
return nums;
}
}
考虑顺序
import java.util.*;
public class Solution {
public int[] reOrderArray (int[] array) {
if (array == null || array.length == 0) return new int[0];
int n = array.length;
for (int i=0; i<n; ++i) {
for (int j=0; j<n; ++j) {
// 左边是偶数, 右边是奇数的情况
if ((array[j] & 1) == 0 && (array[j+1] & 1) == 1) {
int tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
}
}
}
return array;
}
}
import java.util.*;
public class Solution {
public int[] reOrderArray (int[] array) {
// write code here
if(array == null || array.length == 0) return new int[0];
int[] res = new int[array.length];
int index = 0;
for(int i = 0; i < array.length; i++){
if((array[i] & 1) == 1){
res[index++] = array[i];
}
}
for(int i = 0; i < array.length; i++){
if((array[i] & 1) == 0){
res[index++] = array[i];
}
}
return res;
}
}
数值的整数次方
public class Solution {
public double Power(double base, int exponent) {
if(exponent < 0){
exponent = -exponent;
base = 1 / base;
}
return fun(base, exponent);
}
double fun(double x, int n){
if(n == 0) return 1;
double res = fun(x, n / 2);
if(n % 2 == 0){
return res * res;
}else{
return res * res * x;
}
}
}
包含min函数的栈
思路:一个正常栈,一个最小栈,出栈的时候,如果弹出的是就是最小值,则两个栈要同时弹出。
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<>();
Stack<Integer> stack2 = new Stack<>();
public void push(int node) {
stack1.push(node);
if(stack2.isEmpty() || stack2.peek() >= node){
stack2.push(node);
}
}
public void pop() {
if(stack1.peek() == stack2.peek()){
stack1.pop();
stack2.pop();
}else{
stack1.pop();
}
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();
}
}