1、把数组排成最小的数
//输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
//
//
//
// 示例 1:
//
// 输入: [10,2]
//输出: “102”
//
// 示例 2:
//
// 输入: [3,30,34,5,9]
//输出: “3033459”
//
//
//
// 提示:
//
//
// 0 < nums.length <= 100
//
//
// 说明:
//
//
// 输出结果可能非常大,所以你需要返回一个字符串而不是整数
// 拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0
//
// Related Topics 贪心 字符串 排序
采用快速排序的方法进行,排序方法是直接将两个字符串拼接在一起,然后调换顺序再拼接,直接比较这两个字符串,采用的是字符串自带的compareTo函数。
class Solution {
public String minNumber(int[] nums) {
//设计一种排序规则,每两个数从左到右按位依次进行比较,一旦Ai<Bi那么将A放在前面,这样才能最小
//如果比到其中较短的那个数结束都相等就只能再从后进行比较了
String[] strs = new String[nums.length];
for (int i = 0; i < nums.length; i++) {
strs[i] = String.valueOf(nums[i]);
}
quickSort(strs, 0, nums.length-1);
StringBuffer sb = new StringBuffer();
for (String s : strs) {
sb.append(s);
}
return sb.toString();
}
private void quickSort(String[] strs, int l, int r){
if(l >= r) return;
int i = l, j = r;
//选一个作为基准点
String tmp = strs[i];
while(i < j){
//这里采用的是直接拼起来哪个大
//从后往前
while((strs[j] + tmp).compareTo(tmp + strs[j]) >= 0 && i < j) j--;
strs[j] = strs[i];
//从前往后
while((strs[i] + tmp).compareTo(tmp + strs[i]) <= 0 && i < j) i++;
strs[j] = strs[i];
}
strs[i] = tmp;
quickSort(strs, l, i - 1);
quickSort(strs, i + 1, r);
}
}
2、和为s的连续正数序列
//输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
//
//
//
// 示例 1:
//
// 输入:nums = [2,7,11,15], target = 9
//输出:[2,7] 或者 [7,2]
//
//
// 示例 2:
//
// 输入:nums = [10,26,30,31,47,60], target = 40
//输出:[10,30] 或者 [30,10]
//
//
//
//
// 限制:
//
//
// 1 <= nums.length <= 10^5
// 1 <= nums[i] <= 10^6
//
// Related Topics 数组 双指针 二分查找
使用滑动窗口,小于目标时,右窗口向右移动,大于目标时,左窗口向右移动,相等时,几开始建立数组,然后添加进集合中。需要注意的是,只需要遍历到target/2这里就可以判断出所有的可能和为target的连续子序列。
public int[][] findContinuousSequence(int target) {
int i = 1; // 滑动窗口的左边界
int j = 1; // 滑动窗口的右边界
int sum = 0; // 滑动窗口中数字的和
List<int[]> res = new ArrayList<>();
while (i <= target / 2) {
if (sum < target) {
// 右边界向右移动
sum += j;
j++;
} else if (sum > target) {
// 左边界向右移动
sum -= i;
i++;
} else {
// 记录结果
int[] arr = new int[j-i];
for (int k = i; k < j; k++) {
arr[k-i] = k;
}
res.add(arr);
// 左边界向右移动
sum -= i;
i++;
}
}
return res.toArray(new int[res.size()][]);
}
3、把数字翻译成字符串
//给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可
//能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
//
//
//
// 示例 1:
//
// 输入: 12258
//输出: 5
//解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
//
//
//
// 提示:
//
//
// 0 <= num < 231
//
// Related Topics 字符串 动态规划
比较简单的动态规划,主要是看当前数字能否和前面相邻的数字组成一个小于25的数字,如果可以,就需要让dp[i]=dp[i-1]+dp[i-2]
public int translateNum(int num) {
//维护一个数组,dp[i]代表第i位有多少种翻译方法
String s = String.valueOf(num);
int[] dp = new int[s.length()+1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i < s.length()+1; i++) {
//需要判断当前的这个数值和之前的数结合起来会不会形成一个小于等于25的数
if(Integer.parseInt(s.substring(i-2, i)) <= 25 && s.charAt(i-2)-'0' != 0){
dp[i] = dp[i-1]+dp[i-2];
}else{
dp[i] = dp[i-1];
}
}
return dp[s.length()];
}
4、礼物的最大值
//在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直
//到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
//
//
//
// 示例 1:
//
// 输入:
//[
// [1,3,1],
// [1,5,1],
// [4,2,1]
//]
//输出: 12
//解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
//
//
//
// 提示:
//
//
// 0 < grid.length <= 200
// 0 < grid[0].length <= 200
//
// Related Topics 数组 动态规划 矩阵
简单的动态规划
public int maxValue(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = grid[0][0];
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i-1][0] + grid[i][0];
}
for (int i = 1; i < n; i++) {
dp[0][i] = dp[0][i-1] + grid[0][i];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = grid[i][j] + Math.max(dp[i-1][j], dp[i][j-1]);
}
}
return dp[m-1][n-1];
}