文章目录
第五十一题-数组中的逆序对
public class Test36 {
public static int inversePairs(int[] data){
if (data == null ||data.length == 0) throw new IllegalArgumentException("invalid");
int[] copy = new int[data.length];
System.arraycopy(data,0,copy,0,data.length);
return inversePairsCore(data,copy,0,data.length-1);
}
public static int inversePairsCore(int[] data,int[] copy,int start,int end){
if (start == end){
data[start] = copy[end];
return 0;
}
int length = (end -start)/2;
int left = inversePairsCore(data,copy,start,start+length); //递归
int right = inversePairsCore(data,copy,start+length+1,end);
int i = start+length;//第一个数组的末尾
int j = end;//第二个数组的末尾
//拷贝的位置,从后往前拷贝
int indexcopy = end;
//逆序对
int count = 0;
while (i>= start &&j >= start+length+1){
if (data[i]>data[j]){
copy[indexcopy] = data[i];
indexcopy --;
i --;
count += j-(start+length);
}else {
copy[indexcopy] = data[j];
indexcopy --;
j--;
}
}
//把剩余的元素加入到copy中
for (;i>= start;i--){
copy[indexcopy] = data[i];
indexcopy --;
}
for (;j>= start+length+1;j--){
copy[indexcopy] = data[j];
indexcopy --;
}
return count+left+right;
}
public static void main(String[] args) {
int[] data = {1, 2, 3, 4, 7, 6, 5};
System.out.println(inversePairs(data)); // 3
}
}
第五十二题-两个链表的第一个公共节点
public class Test37 {
public static ListNode findFirstCommonNode(ListNode head1,ListNode head2){
int length1 = getLength(head1);
int length2 = getLength(head2);
int diff = length1 - length2;
ListNode longNode = head1;
ListNode shortNode = head2;
if (diff < 0){
longNode = head2;
shortNode = head1;
diff = -diff;
}
for (int i =0;i<diff;i++){
longNode = longNode.next;
}
while (longNode != null && shortNode != null && longNode != shortNode){
longNode = longNode.next;
shortNode = shortNode.next;
}
return longNode;
}
public static int getLength(ListNode head){
ListNode temp = head;
int res =0;
while(temp != null){
temp = temp.next;
res ++;
}
return res;
}
public static void main(String[] args) {
ListNode n1 = new ListNode(1);
ListNode n2 = new ListNode(2);
ListNode n3 = new ListNode(3);
ListNode n4 = new ListNode(4);
ListNode n5 = new ListNode(5);
ListNode n6 = new ListNode(6);
ListNode n7 = new ListNode(7);
n1.next = n2;
n2.next = n3;
n3.next = n6;
n6.next = n7;
n4.next = n5;
n5.next = n6;
System.out.println(findFirstCommonNode(n1, n4).val);
}
}
第五十三题-在排序数组中查找数字
public class Test38 {
//找到k第一次出现的位置
public static int getFirst(int[] data,int k,int start,int end){
if (data == null ||data.length == 0 || start > end) return -1;
int minIndex = start + (end -start)/2;
if (minIndex > data.length-1) return minIndex;
int minData = data[minIndex];
if (minData == k){
if (minIndex > 0 && data[minIndex-1] != k || minIndex == 0) return minIndex;
else end = minIndex-1;//在前半段寻找
}
else if (minData > k) end = minIndex -1;
else start = minIndex +1;
return getFirst(data,k,start,end);
}
//找到k最后出现的位置
public static int getLast(int[] data,int k,int start,int end){
if (data == null ||data.length == 0 || start > end) return -1;
int minIndex = start + (end -start)/2;
if (minIndex > data.length-1) return minIndex;
int minData = data[minIndex];
if (minData == k){
if (minIndex < data.length-1 && data[minIndex+1] != k ||minIndex == data.length-1) return minIndex;
else start = minIndex+1;
}else if (minData > k) end = minIndex -1;
else start = minIndex + 1;
return getLast(data,k,start,end);
}
public static int getNumberOfK(int[] data,int k){
int number = 0;
if (data != null && data.length > 0){
int first = getFirst(data,k,0,data.length-1);
int last = getLast(data,k,0,data.length-1);
if (first > -1 && last > -1 ){
number = last-first+1;
}
}
return number;
}
public static void main(String[] args) {
// 查找的数字出现在数组的中间
int[] data1 = {1, 2, 3, 3, 3, 3, 4, 5};
System.out.println(getNumberOfK(data1, 3)); // 4
// 查找的数组出现在数组的开头
int[] data2 = {3, 3, 3, 3, 4, 5};
System.out.println(getNumberOfK(data2, 3)); // 4
// 查找的数组出现在数组的结尾
int[] data3 = {1, 2, 3, 3, 3, 3};
System.out.println(getNumberOfK(data3, 3)); // 4
// 查找的数字不存在
int[] data4 = {1, 3, 3, 3, 3, 4, 5};
System.out.println(getNumberOfK(data4, 2)); // 0
// 查找的数字比第一个数字还小,不存在
int[] data5 = {1, 3, 3, 3, 3, 4, 5};
System.out.println(getNumberOfK(data5, 0)); // 0
// 查找的数字比最后一个数字还大,不存在
int[] data6 = {1, 3, 3, 3, 3, 4, 5};
System.out.println(getNumberOfK(data6, 0)); // 0
// 数组中的数字从头到尾都是查找的数字
int[] data7 = {3, 3, 3, 3};
System.out.println(getNumberOfK(data7, 3)); // 4
// 数组中的数字从头到尾只有一个重复的数字,不是查找的数字
int[] data8 = {3, 3, 3, 3};
System.out.println(getNumberOfK(data8, 4)); // 0
// 数组中只有一个数字,是查找的数字
int[] data9 = {3};
System.out.println(getNumberOfK(data9, 3)); // 1
// 数组中只有一个数字,不是查找的数字
int[] data10 = {3};
System.out.println(getNumberOfK(data10, 4)); // 0
}
}
第五十四题-二叉搜索树的第K大节点
public class Test54 {
//逆中序遍历方式
private static int ans = 0, count = 0;
public static int kthLargest(TreeNode root, int k) {
dfs(root, k);
return ans;
}
private static void dfs(TreeNode root, int k) {
if (root.right != null) dfs(root.right, k);
if (++count == k) {
ans = root.val;
return;
}
if (root.left != null) dfs(root.left, k);
}
public static void main(String[] args) {
TreeNode root = new TreeNode();
root.val = 5;
root.left = new TreeNode();
root.left.val = 3;
root.right = new TreeNode();
root.right.val = 7;
root.left.left = new TreeNode();
root.left.left.val = 2;
root.left.right = new TreeNode();
root.left.right.val = 4;
root.right.left = new TreeNode();
root.right.left.val = 6;
root.right.right = new TreeNode();
root.right.right.val = 8;
System.out.println(kthLargest(root, 3));
}
}
第五十五题-二叉树的深度
public class Test39 {
//解法一
public static int treeDepth(TreeNode root){
if (root == null) return 0;
int left = treeDepth(root.left);
int right = treeDepth(root.right);
return left> right?(left+1) :(right+1);
}
public static boolean isBalanced(TreeNode root){
if (root == null) return true;
int left = treeDepth(root.left);
int rigth = treeDepth(root.right);
int diff = left - rigth;
if (diff > 1 ||diff < -1)return false;
return isBalanced(root.left) && isBalanced(root.right);
}
/*
用后序遍历的方式遍历二叉树的每一个结点,在遍历到一个结点之前我们就已经遍历了它的左右子树。
只要在遍历每个结点的时候记录它的深度(某一结点的深度等于它到叶节点的路径的长度),
我们就可以一边遍历一边判断每个结点是不是平衡的。
*/
//解法二
public static boolean isBalanced2(TreeNode root){
int[] depth = new int[1];
return isBalancedHelper(root,depth);
}
public static boolean isBalancedHelper(TreeNode root,int[] depth){
if (root == null){//如果为空,则返回true
depth[0] = 0;
return true;
}
int[] left = new int[1];//记录左子树的深度
int[] right = new int[1];//记录右子树的深度
if (isBalancedHelper(root.left,left) && isBalancedHelper(root.right,right)){//如果是平衡树
int diff = left[0] - right[0];//计算深度
if (diff >= -1 && diff <= 1){//如果当前位置也是平衡树
depth[0] = 1+(left[0] > right[0]? left[0] : right[0]);
return true;
}
}
return false;
}
public static void main(String[] args) {
TreeNode root = new TreeNode();
root.val = 1;
root.left = new TreeNode();
root.left.val = 2;
root.right = new TreeNode();
root.right.val = 3;
root.left.left = new TreeNode();
root.left.left.val = 4;
root.left.right = new TreeNode();
root.left.right.val = 5;
root.right.left = new TreeNode();
root.right.left.val = 6;
root.right.right = new TreeNode();
root.right.right.val = 7;
System.out.println(treeDepth(root));
System.out.println(isBalanced(root));
System.out.println(isBalanced2(root));
System.out.println("-----------------------");
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(1);
TreeNode n3 = new TreeNode(1);
TreeNode n4 = new TreeNode(1);
TreeNode n5 = new TreeNode(1);
TreeNode n6 = new TreeNode(1);
TreeNode n7 = new TreeNode(1);
n1.left = n2;
n1.right = n3;
n2.left = n4;
n2.right = n5;
n5.left = n7;
System.out.println(isBalanced(n1));
System.out.println(isBalanced2(n1));
System.out.println("----------------");
}
}
第五十六题-数组中只出现一次的数字
public class Test40 {
public static int[] findNumbersAppearanceOnce(int[] data){
int[] res = {0,0};
if (data == null ||data.length < 2) return res;
int xor = 0;
//把data数组里面的是进行异或
for (int i : data){
xor ^= i;
}
//找到位置n
int index = findFirstBit1(xor);
for (int i : data){
if (isBit1(i,index)){//如果在第一个分组中,把全部的进行异或,得到唯一的数
res[0] ^= i;
}else res[1] ^=i;//如果在第二个分组中,
}
return res;
}
public static int findFirstBit1(int num){
int index = 0;
//一共三十二位
while((num & 1) == 0 && index < 32){
num >>>=1;//无符号右移一位
index ++;
}
return index;
}
public static boolean isBit1(int num, int indexBit){
num >>>= indexBit;
return (num & 1) == 1;
}
public static void main(String[] args) {
int[] data1 = {2, 4, 3, 6, 3, 2, 5, 5};
int[] result1 = findNumbersAppearanceOnce(data1);
System.out.println(result1[0] + " " + result1[1]);
int[] data3 = {4, 6, 1, 1, 1, 1};
int[] result3 = findNumbersAppearanceOnce(data3);
System.out.println(result3[0] + " " + result3[1]);
}
}
第五十七题-和为s的两个数字VS和为s的连续正数序列
import java.util.ArrayList;
import java.util.List;
public class Test41 {
public static List<Integer> findNumbersWithSum(int[] data,int sum){
List<Integer> res = new ArrayList<>();
if (data == null ||data.length < 2) return res;
int start = 0;
int end = data.length-1;
long cursum;
while (start < end){
cursum = data[start] + data[end];
if (cursum == sum) {
res.add(data[start]);
res.add(data[end]);
break;
}else if (cursum > sum){
end --;
}else
start ++;
}
return res;
}
public static List<List<Integer>> findContinuousSequence(int sum){
List<List<Integer>> res = new ArrayList<>();
if (sum < 3){
return res;
}
int samll = 1;
int big = 2;
int mid = (1+sum)/2;
int cumsum = samll + big;
while(samll < mid){
if (cumsum == sum){
List<Integer> list = new ArrayList<>();
for(int i = samll;i <= big; i++){
list.add(i);
}
res.add(list);
}
while (cumsum > sum && samll < mid){
cumsum -= samll;
samll ++;
if (cumsum == sum){
List<Integer> list = new ArrayList<>();
for(int i = samll;i <= big; i++){
list.add(i);
}
res.add(list);
}
}
big++;
cumsum += big;
}
return res;
}
public static void main(String[] args) {
int[] data1 = {1, 2, 4, 7, 11, 15};
System.out.println(findNumbersWithSum(data1, 15));
System.out.println(findContinuousSequence(15));
}
}
第五十八题-翻转单词顺序VS左旋转字符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7DKQPfyB-1650790433073)(C:/Users/77/AppData/Roaming/Typora/typora-user-images/image-20220420082606627.png)]
public class Test42 {
//范围内的字符进行翻转
public static void reverse(char[] data,int start,int end){
if (data == null || data.length == 0 || start < 0|| end > data.length-1 || start > end) return;
while (start < end){
char temp = data[start];
data[start] = data[end];
data[end] = temp;
start ++;
end --;
}
}
public static char[] reverseSentence(char[] data){
if (data == null || data.length ==0) return data;
reverse(data,0,data.length-1); //翻转全部的字符
int start = 0;
int end = 0;
while (start < data.length){
if (data[start] == ' '){
start ++;
end ++;
}else if (end == data.length || data[end] == ' '){
reverse(data,start,end-1);//翻转单个单词
end ++;
start = end;
}else end ++;
}
return data;
}
public static char[] leftRotateString(char[] data,int n){
if (data == null || data.length == 0 || n < 0 || n >data.length) return data;
reverse(data,0,n-1);
reverse(data,n,data.length-1);
reverse(data,0,data.length-1);
return data;
}
public static void main(String[] args) {
System.out.println(new String(reverseSentence("I am a student.".toCharArray())));
System.out.println(new String(reverseSentence("Wonderful".toCharArray())));
System.out.println(new String(leftRotateString("abcdefg".toCharArray(), 2)));
System.out.println(new String(leftRotateString("abcdefg".toCharArray(), 1)));
System.out.println(new String(leftRotateString("abcdefg".toCharArray(), 6)));
System.out.println(new String(leftRotateString("abcdefg".toCharArray(), 7)));
System.out.println(new String(leftRotateString("abcdefg".toCharArray(), 0)));
}
}
第五十九题-队列的最大值
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
public class Test59 {
public static List<Integer> maxInWindows(List<Integer> data, int size){
List<Integer> windowMax = new ArrayList<>();
// 条件检查
if (data == null || size < 1 || data.size() < 1) {
return windowMax;
}
//存储索引值
Deque<Integer> deq = new LinkedList<>();
//窗口还没有被填满时,找到最大值的索引
for (int i = 0; i< size && i < data.size();i++){
// 如果索引对应的值比之前存储的索引值对应的值大或者相等,就删除之前存储的值
while (!deq.isEmpty() && data.get(i) >= data.get(deq.getLast()))
deq.removeLast();
//否则将索引添加到队列的末尾,或者队列已经清空,将最大值放入队列
deq.addLast(i);
}
for (int i = size;i < data.size();i++){
//第一个窗口的最大值保存
windowMax.add(data.get(deq.getFirst()));
// 如果索引对应的值比之前存储的索引值对应的值大或者相等,就删除之前存储的值
while (!deq.isEmpty() && data.get(i) >= data.get(deq.getLast()))
deq.removeLast();
//删除已经画出窗口的数据对应的下标
if(!deq.isEmpty() &&deq.getFirst() <= (i-size)) deq.removeFirst();
//将可能的最大值放入队尾
deq.add(i);
}
windowMax.add(data.get(deq.getFirst()));//最后一个串口的最大值
return windowMax;
}
private static List<Integer> arrayToCollection(int[] array) {
List<Integer> result = new LinkedList<>();
if (array != null) {
for (int i : array) {
result.add(i);
}
}
return result;
}
public static void main(String[] args) {
// expected {7};
List<Integer> data1 = arrayToCollection(new int[]{1, 3, -1, -3, 5, 3, 6, 7});
System.out.println(data1 + "," + maxInWindows(data1, 10));
// expected {3, 3, 5, 5, 6, 7};
List<Integer> data2 = arrayToCollection(new int[]{1, 3, -1, -3, 5, 3, 6, 7});
System.out.println(data2 + "," + maxInWindows(data2, 3));
}
}
第六十题-n个骰子的点数
public class Test43 {
/**
* 递归求解
* @param number 个数
* @param max 最大点
*/
public static void printProbability(int number,int max){
if (number < 1 || max <1){
return;
}
int maxSum = number * max;
int[] probabilities = new int[maxSum - number +1];
probability(number,probabilities,max);
double total = 1;
//计算骰子的全排列
for (int i = 0; i < number; i++) {
total *= max;
}
//计算概率
for (int i = number; i <= maxSum; i++) {
double ratio = probabilities[i - number] / total;
System.out.printf("%-8.4f", ratio);
}
System.out.println();
}
/**
* @param number 骰子个数
* @param probabilities 不同骰子数出现次数的计数数组
* @param max 骰子最大值
*/
public static void probability(int number,int[] probabilities,int max){
for (int i = 1; i<= max;i++){//第一个骰子可能出现的点数
probability(number,number,i,probabilities,max);
}
}
/**
* @param original 骰子的总数
* @param current 剩余要处理的骰子
* @param sum 前面的总和
* @param probabilities 不同骰子数出现次数的计数数组
* @param max 最大值
*/
public static void probability(int original, int current, int sum, int[] probabilities, int max){
//当处理到最后一个骰子的时候,就把和放入,次数++
if (current == 1)probabilities[sum-original]++; //和为sum的点数,增加
else {
//处理剩下的骰子
for (int i = 1;i<= max;i++){
probability(original,current-1,sum+i,probabilities,max);
}
}
}
public static void printProbability2(int number,int max){
if (number < 1 || max <1){
return;
}
//定义一个二维数组
int[][] probabilities = new int[2][max*number+1];
//初始化数据
for (int i = 0; i<max*number+1;i++){
probabilities[0][i] = 0;
probabilities[1][i] = 0;
}
//标记当前要使用的是第0个数组还是第1个数组
int flag = 0;
//抛出第一个骰子时出现的各种情况
for (int i = 1; i<= max;i++){
probabilities[flag][i] = 1;
}
//抛出其他骰子
for(int k = 2;k<= number;k++){
// 如果抛出了k个骰子,那么和为[0, k-1]的出现次数为0
for (int i = 1; i<k;i++){
probabilities[1-flag][i] = 0;
}
//抛出k个骰子所有可能的和
for(int j = k; j<=number*max;j++){
probabilities[1-flag][j] = 0; //清0
for (int m = 1; m<= j && m<=max;m++){
//求出当前数组可能出现的和
probabilities[1-flag][j] += probabilities[flag][j-m];
}
}
flag = 1-flag;
}
double total= 1;
for (int i = 0;i<number;i++) total *= max;
int maxSum = number*max;
for (int i = number;i<= maxSum;i++){
double ratio = probabilities[flag][i] / total;
System.out.printf("%-8.4f",ratio);
}
}
public static void main(String[] args) {
printProbability(3, 6);
System.out.println();
printProbability2(3, 6);
}
}
第六十一题-打扑克牌的顺子
import java.util.Arrays;
public class Test44 {
public static boolean isContinuous(int[] numbers){
if (numbers == null || numbers.length < 0) return false;
Arrays.sort(numbers); //排序
int numberZeros = 0;
int numberOfGap = 0;
for (int i = 0; i<numbers.length && numbers[i] == 0;i++) numberZeros ++ ;
if (numberZeros > 2) return false;
//第一个非0元素的位置
int samll = numberZeros;
int big = samll+1;
while (big < numbers.length){
if (numbers[samll] == numbers[big]) return false;
numberOfGap += numbers[big] - numbers[samll] -1;
samll = big;
big ++;
}
return numberOfGap <= numberZeros;
}
public static void main(String[] args) {
int[] numbers1 = {1, 3, 2, 5, 4};
System.out.println(isContinuous(numbers1));
int[] numbers2 = {1, 3, 2, 6, 4};
System.out.println(isContinuous(numbers2));
int[] numbers3 = {0, 3, 2, 6, 4};
System.out.println(isContinuous(numbers3));
}
}
第六十二题-圆圈中最后剩下的数字
import java.util.ArrayList;
import java.util.List;
public class Test45 {
public static int lastRemaining(int n ,int m){
if (n < 1 || m< 1) return -1;
List<Integer> list = new ArrayList<>();
for (int i = 0; i< n;i++){
list.add(i);
}
//要删除的位置
int index = 0;
int start = 0;//开始的位置
while (list.size() > 1){
//移动m-1次就到了要删除的点
for (int i = 1;i<m;i++){
index = (index+1)%list.size();
}
list.remove(index);
}
return list.get(0);
}
public static int lastRemaining2(int n,int m){
if (n < 1 || m< 1) return -1;
int last = 0;
for (int i = 2; i<=n;i++){
last = (last+m)%i;
}
return last;
}
public static void main(String[] args) {
System.out.println(lastRemaining(5, 3)); // 最后余下3
System.out.println(lastRemaining(5, 2)); // 最后余下2
System.out.println(lastRemaining(6, 7)); // 最后余下4
System.out.println(lastRemaining(6, 6)); // 最后余下3
System.out.println(lastRemaining(0, 0)); // 最后余下-1
System.out.println("--------------");
System.out.println(lastRemaining2(5, 3)); // 最后余下3
System.out.println(lastRemaining2(5, 2)); // 最后余下2
System.out.println(lastRemaining2(6, 7)); // 最后余下4
System.out.println(lastRemaining2(6, 6)); // 最后余下3
System.out.println(lastRemaining2(0, 0)); // 最后余下-1
}
}
第六十三题-股票的最大利润
public class Test63 {
public static int maxProfit(int[] prices) {
if(prices == null || prices.length <= 1) {
return 0;
}
int res = 0, min = prices[0];
for(int i = 1; i < prices.length; i++) {
if(prices[i] <= min) {
min = prices[i];// 如果是股票历史最低价,那么便赋值
}else {
res = Math.max(res, prices[i] - min);
}
}
return res;
}
public static void main(String[] args) {
int[] prices = {7,1,5,3,6,4};
System.out.println(maxProfit(prices));
}
}
第六十四题-求1+2+…n
class Test46{
public static int sum_s(int n){
int sum = n;
boolean res = (n>0) &&((sum += sum_s(n-1)) > 0);
return sum;
}
public static void main(String[] args) {
System.out.println(sum_s(4));
}
}
利用两个函数来实现递归,第一个函数作为终止条件,第二个函数作为递归函数,n大于0执行第二个函数,n小于递归终止
第六十五题-不用加减乘除做加法
public class Test47 {
public static int add(int x,int y){
int sum;
int carry;
do {
sum = x ^ y;//不同为1,相同为0
carry = (x & y) << 1;//进位的产生等同于,x和y做与运算之后,两个1生成了1,然后向左移位
x = sum;
y = carry;
}while (y != 0); //直到不产生进位为止
return x;
}
public static void main(String[] args) {
System.out.println(add(1, 2) + ", " + (1 + 2));
System.out.println(add(13, 34)+ ", " + (13 + 34));
System.out.println(add(19, 85)+ ", " + (19 + 95));
System.out.println(add(865, 245)+ ", " + (865 + 245));
}
}