剑指 Offer 17. 打印从1到最大的n位数
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
题解
class Solution {
int[] res;
int nine = 0, count = 0, start, n;
char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
public int[] printNumbers(int n) {
this.n = n;
res = new int[(int)Math.pow(10, n) - 1];
num = new char[n];
start = n - 1;
dfs(0);
return res;
}
void dfs(int x) {
if(x == n) {
String s = String.valueOf(num).substring(start);
if(!s.equals("0")) res[count++] = Integer.parseInt(s);
if(n - start == nine) start--;
return;
}
for(char i : loop) {
if(i == '9') nine++;
num[x] = i;
dfs(x + 1);
}
nine--;
}
}
该题考点在于大数问题
class Solution {
StringBuilder res;
int nine = 0, count = 0, start, n;
char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
public String printNumbers(int n) {
this.n = n;
res = new StringBuilder();
num = new char[n];
start = n - 1;
dfs(0);
res.deleteCharAt(res.length() - 1);
return res.toString();
}
void dfs(int x) {
if(x == n) {
String s = String.valueOf(num).substring(start);
if(!s.equals("0")) res.append(s + ",");
if(n - start == nine) start--;
return;
}
for(char i : loop) {
if(i == '9') nine++;
num[x] = i;
dfs(x + 1);
}
nine--;
}
}
剑指 Offer 51. 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
题解
利用归并排序。
分: 不断将数组从中点位置划分开(即二分法),将整个数组的排序问题转化为子数组的排序问题;
治: 划分到子数组长度为 1 时,开始向上合并,不断将 较短排序数组 合并为 较长排序数组,直至合并至原数组时完成排序;
class Solution {
int sum = 0;
public int reversePairs(int[] nums) {
merge(nums, 0, nums.length - 1);
return sum;
}
public void merge(int[] nums, int left, int right){
int mid = left + ((right - left) >> 1);
if(left < right){
merge(nums, left, mid);
merge(nums, mid + 1, right);
mergeSort(nums, left, mid, right);
}
}
public void mergeSort(int[] nums, int left, int mid, int right){
int[] arr = new int[right - left + 1]; // 保留合并后的有序数组,覆盖掉原来的
int idx = 0, i = left, j = mid + 1;
while(i <= mid && j <= right){ // 遍历左右两边, 选择排序
if(nums[i] <= nums[j]){ // 将左边较小数放入数组中
arr[idx++] = nums[i++];
}else{ // 右边更小
// 统计逆序对的个数
sum += mid - i + 1; // 因为左右两边都是有序的,nums[i]>nums[j],则左边[i,mid]的值都大于nums[j],逆序对个数为 mid - i + 1
arr[idx++] = nums[j++]; // 把较小数放入数组中
}
}
//把左边剩余放入数组中
while(i <= mid){
arr[idx++] = nums[i++];
}
//把右边剩余放入数组中
while(j <= right){
arr[idx++] = nums[j++];
}
// 将排好序的合并数组覆盖nums数组中原来的范围
for(int k = 0; k < arr.length; k++){
nums[k + left] = arr[k];
}
}
}