arrayMap = new HashMap<>();
for (int i = 0; i < n; i++) {
int num = nums[i];
int targetVal = target - num;
arrayMap.put(targetVal, i);
}
for (int i = 0; i < n; i++) {
int num = nums[i];
if (arrayMap.containsKey(num)) {
int index = arrayMap.get(num);
if (index > i) {
return new int[]{i, index};
} else {
return new int[]{index, i};
}
}
}
return new int[0];
}
/**
* 暴力破解法
* 时间复杂度:o(n^2)
* 空间复杂度:O(n)
* @param nums
* @param target
* @return
*/
private int[] forceSolution(int[] nums, int target) {
int n = nums.length;
for (int i = 0; i < n; i++) {
int num = nums[i];
int val = target - num;
for (int j = i + 1; j < n; j++) {
if (nums[j] == val) {
return new int[]{i, j};
}
}
}
return new int[0];
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSumII.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode;
/**
* @Description
* @Author luohaiyang
* @Date 2022/4/28
*/
public class TwoSumII {
public int[] twoSum(int[] numbers, int target) {
return twoPointer(numbers, target);
}
/**
* 双指针
* 时间复杂度:O(n)
* 空间复杂度:O(1)
* @param numbers
* @param target
* @return
*/
private int[] twoPointer(int[] numbers, int target) {
int n = numbers.length;
if (n < 2) {
return numbers;
}
int i = 0, j = n - 1;
while (i < j) {
if (numbers[i] + numbers[j] == target) {
return new int[]{i + 1, j + 1};
}
if (numbers[i] + numbers[j] > target) {
j--;
} else {
i++;
}
}
return new int[0];
}
/**
* 暴力法:
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
* @param numbers
* @param target
* @return
*/
private int[] forceSolution(int[] numbers, int target) {
int n = numbers.length;
if (n < 2) {
return numbers;
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (numbers[i] + numbers[j] == target) {
return new int[]{i + 1, j + 1};
}
}
}
return new int[0];
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
/**
*
* 125
*
* 验证回文串
*
* https://leetcode-cn.com/problems/valid-palindrome/
*
*
* @author LuoHaiYang
*/
public class IsPalindrome {
public boolean isPalindrome(String str) {
int head = 0, tail = str.length() - 1;
char a, b;
while(head < tail) {
a = str.charAt(head);
b = str.charAt(tail);
if(!Character.isLetterOrDigit(a)) {
head ++;
} else if(!Character.isLetterOrDigit(b)) {
tail --;
} else {
if(Character.toLowerCase(a) != Character.toLowerCase(b)) {
return false;
}
head ++;
tail --;
}
}
return true;
}
public static void main(String[] args) {
IsPalindrome isPalindrome = new IsPalindrome();
String test = "race a car";
System.out.println(isPalindrome.isPalindrome(test));
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.Arrays;
/**
* 最大间距
*
* url:https://leetcode-cn.com/problems/maximum-gap/
*
* @author LuoHaiYang
*/
public class MaximumGap {
/**
* 基于桶排序
* 时间复杂度:O(N)
* 空间复杂度:O(N)
* @param nums
* @return
*/
public int maximumGapOptimize2(int[] nums) {
if (nums.length < 2) return 0;
int len = nums.length;
// 找出最大值和最小值 为了方便后面确定桶的数量
int max = -1, min = Integer.MAX_VALUE;
for (int i = 0; i < len; i++) {
max = Math.max(nums[i], max);
min = Math.min(nums[i], min);
}
// 排除nums全部为一样的数字,nums = [1,1,1,1,1,1];
if (max - min == 0) return 0;
// 用于存放每个桶的最大值
int[] bucketMin = new int[len - 1];
// 用于存放每个桶的最小值
int[] bucketMax = new int[len - 1];
Arrays.fill(bucketMax, -1);
Arrays.fill(bucketMin, Integer.MAX_VALUE);
// 确定桶的间距
int interval = (int)Math.ceil((double)(max - min) / (len - 1));
for (int i = 0; i < len; i++) {
// 找到每一个值所对应桶的索引
int index = (nums[i] - min) / interval;
if (nums[i] == min || nums[i] == max) continue;
// 更新每个桶的数据
bucketMax[index] = Math.max(bucketMax[index], nums[i]);
bucketMin[index] = Math.min(bucketMin[index], nums[i]);
}
// maxGap 表示桶之间最大的差距
int maxGap = 0;
// preMax 表示前一个桶的最大值
int preMax = min;
for (int i = 0; i < len - 1; i++) {
// 表示某一个桶为空
// 但凡某一个桶不为空,都会在前面的数据中更新掉bucketMax的值
if (bucketMax[i] == -1) continue;
maxGap = Math.max(bucketMin[i] - preMax, maxGap);
preMax = bucketMax[i];
}
// [1,10000000]
maxGap = Math.max(maxGap, max - preMax);
return maxGap;
}
/**
* 基数排序:
* 时间复杂度:O(N)
* 空间复杂度:O(N)
* @param nums
* @return
*/
public int maximumGapOptimize(int[] nums) {
int n = nums.length;
if (n < 2) {
return 0;
}
long exp = 1;
int[] buf = new int[n];
int maxVal = Arrays.stream(nums).max().getAsInt();
while (maxVal >= exp) {
int[] cnt = new int[10];
for (int i = 0; i < n; i++) {
int digit = (nums[i] / (int) exp) % 10;
cnt[digit]++;
}
for (int i = 1; i < 10; i++) {
cnt[i] += cnt[i - 1];
}
for (int i = n - 1; i >= 0; i--) {
int digit = (nums[i] / (int) exp) % 10;
buf[cnt[digit] - 1] = nums[i];
cnt[digit]--;
}
System.arraycopy(buf, 0, nums, 0, n);
exp *= 10;
}
int ret = 0;
for (int i = 1; i < n; i++) {
ret = Math.max(ret, nums[i] - nums[i - 1]);
}
return ret;
}
public int maximumGap(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
// 排序
quickSort(nums);
int n = nums.length;
int max = nums[1] - nums[0];
for (int i = 2; i < n; i++) {
max = max(max, nums[i] - nums[i-1]);
}
return max;
}
private void quickSort(int[] nums) {
int n = nums.length;
quickSort3ways(nums, 0, n-1);
}
private void quickSort3ways(int[] nums, int left, int right) {
if (left >= right) {
return;
}
int p = nums[left];
int i = left + 1, lt = left, gt = right + 1;
while (i < gt) {
if (nums[i] < p) {
swap(nums, i, lt + 1);
i++;
lt++;
} else if (nums[i] > p) {
swap(nums, i, gt - 1);
gt--;
} else {
i++;
}
}
swap(nums, left, lt);
quickSort3ways(nums, left, lt - 1);
quickSort3ways(nums, gt, right);
}
private int max(int i, int j) {
return Math.max(i, j);
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public static void main(String[] args) {
int[] test = {3,6,9,1,20,15,11,30,31};
MaximumGap maximumGap = new MaximumGap();
// System.out.println(maximumGap.maximumGap(test));
System.out.println(maximumGap.maximumGapOptimize2(test));
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumProductSubarray.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
/**
* @author LuoHaiYang
* @Date 2020-05-18
*
* url: https://leetcode-cn.com/problems/maximum-product-subarray/
*
*/
public class MaximumProductSubarray {
/**
* 问题1 :算法没有包括数组头部元素的比较;
* 问题2 : 数组没有考虑到每个元素本身大小的比较;
*
*
* @param nums
* @return
*/
public int maxProduct(int[] nums) {
// 2, 3, -2, 4, 5, 8, -1, -3, 10
// [ ]
//
int length = nums.length;
if (length == 1) {
return nums[0];
}
if (length == 2) {
int result = nums[0] * nums[1];
int anotherResult = nums[0] > nums[1] ? nums[0] : nums[1];
return result > anotherResult ? result : anotherResult;
}
int max = nums[0] * nums[1] > nums[0] ? nums[0] * nums[1] : nums[0];
for (int i = 0; i < length; i++) {
int[] mul = new int[length];
for (int j = i; j < length; j++) {
mul[j] = nums[j];
}
for (int j = i + 1; j < length; j++) {
int result = nums[j] * mul[j-1];
//mul[j] = mul[j] > result ? mul[j] : result;
mul[j] = result;
if (nums[j] > max) {
max = nums[j];
}
if (result > max) {
max = result;
}
}
}
return max;
}
public static void main(String[] args) {
MaximumProductSubarray maximumProductSubarray = new MaximumProductSubarray();
int[] nums = {2, -1, 1, 1};
//int[] nums = {2, 3, -2, 4, 5, 8, -1, -3, 10};
System.out.println(maximumProductSubarray.maxProduct(nums));
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReversePairs.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.Arrays;
/**
* 逆序对
*
* url: https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
*
* @author LuoHaiYang
*/
public class ReversePairs {
/* ================================ 解法一 ================================*/
/**
* 暴力解法O(n^2),超时
*
* @param nums
* @return
*/
public int reversePairs2(int[] nums) {
int n = nums.length;
if (n < 2) {
return 0;
}
int reverseNum = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] > nums[j]) {
reverseNum++;
}
}
}
return reverseNum;
}
/* ================================ 解法二 ================================*/
/**
* 使用自顶向下的归并排序算法计算逆序对,用来额外的空间。
*
* @param nums
* @return
*/
public int reversePairs(int[] nums) {
int n = nums.length;
if (n < 2) {
return 0;
}
return getReversePairs(nums);
}
private int getReversePairs(int[] nums) {
int n = nums.length;
return getReversePairs(nums, 0, n - 1);
}
private int getReversePairs(int[] nums, int left, int right) {
if (left >= right) {
return 0;
}
int result = 0;
int mid = (left + right) / 2;
result += getReversePairs(nums, left, mid) + getReversePairs(nums, mid + 1, right) + reversePairs(nums, left, mid, right);
return result;
}
private int reversePairs(int[] nums, int left, int mid, int right) {
int[] aux = Arrays.copyOfRange(nums, left, right + 1);
int i = left, j = mid + 1;
int res = 0;
for (int k = left; k <= right; k++) {
if (i > mid) {
nums[k] = aux[j - left];
j++;
} else if (j > right) {
nums[k] = aux[i - left];
i++;
} else if (aux[i - left] <= aux[j - left]) {
nums[k] = aux[i - left];
i++;
} else {
nums[k] = aux[j - left];
j++;
res += (mid - i) + 1;
}
}
return res;
}
/* ================================ 题解三(优化) ================================*/
/**
*
* 相比解法二时间复杂度常数和空间复杂度更低
*
* @param nums
* @return
*/
public int reversePairs3(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
int[] temp = new int[nums.length];
System.arraycopy(nums, 0, temp, 0, nums.length);
int count = mergeCount(nums, temp, 0, nums.length - 1);
return count;
}
private int mergeCount(int[] nums, int[] temp, int start, int end) {
if (start >= end) {
return 0;
}
int mid = (start + end) >> 1;
int left = mergeCount(temp, nums, start, mid);
int right = mergeCount(temp, nums, mid + 1, end);
int count = 0;
//merge()
//遍历左区域指针
int i = mid;
//遍历右区域指针
int j = end;
//临时区域指针
int k = end;
while (i >= start && j >= mid + 1) {
if (nums[i] > nums[j]) {
count += j - mid;
temp[k--] = nums[i--];
} else {
temp[k--] = nums[j--];
}
}
//如果还有剩下没遍历的
while (i >= start) {
temp[k--] = nums[i--];
}
while (j >= mid + 1) {
temp[k--] = nums[j--];
}
return count + left + right;
}
public int reversePairs4(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
int[] temp = new int[nums.length];
System.arraycopy(nums, 0, temp, 0, nums.length);
//int count = mergeCount2();
return 0;
}
private int mergeCount2(int[] nums, int[] temp, int start, int end) {
if (start >= end) {
return 0;
}
int mid = (start + end) << 1;
//int left = mergeCount2(nums, );
return 0;
}
public static void main(String[] args) {
ReversePairs reversePairs = new ReversePairs();
int[] nums = {7, 5, 6, 4};
//int[] nums = {1,3,2,3,1};
System.out.println(reversePairs.reversePairs3(nums));
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ReverseVowels.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
/**
*
* 345
*
* https://leetcode-cn.com/problems/reverse-vowels-of-a-string/
*
* 反转字符串中的元音字母
*
* @author LuoHaiYang
*/
public class ReverseVowels {
public String reverseVowels(String s) {
char[] arr = s.toCharArray();
int n = arr.length, left = 0, right = n - 1;
while (left <= right) {
// 如果不是元音,则指针右移
while (left < n && !isVowel(arr[left])) {
left++;
}
while (right >= 0 && !isVowel(arr[right])) {
right--;
}
if (left > right) {
break;
}
// 字符调换
swap(arr, left, right);
left++;
right--;
}
return new String(arr);
}
/**
*
* 1. 元音字母是?
*
*/
private boolean isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u'
|| ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U';
}
private void swap(char[] arr, int i, int j) {
char tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SortColors.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
/**
*
* 颜色分类
*
* url:https://leetcode-cn.com/problems/sort-colors/
*
* @author LuoHaiYang
*/
public class SortColors {
public void sortColors(int[] nums) {
if (nums == null || nums.length < 2) {
return;
}
sort(nums, 0, nums.length - 1);
}
private void sort(int[] nums, int left, int right) {
if (left >= right) {
return;
}
int p = nums[left];
int i = left + 1, lt = left, gt = right + 1;
while (i < gt) {
if (nums[i] < p) {
swap(nums, i, lt + 1);
i++;
lt++;
} else if (nums[i] > p) {
swap(nums, i, gt - 1);
gt--;
} else {
i++;
}
}
swap(nums, left, lt);
sort(nums, left, lt - 1);
sort(nums, gt, right);
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public static void main(String[] args) {
SortColors sortColors = new SortColors();
int[] test = {0, 1};
sortColors.sortColors(test);
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/SubarraySumEqualsK.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.HashMap;
import java.util.Map;
/**
* @author LuoHaiYang
*
* @Date 2020-05-15
* 560. Subarray Sum Equals K
* url: https://leetcode-cn.com/problems/subarray-sum-equals-k/
*
*
*/
public class SubarraySumEqualsK {
/**
* O (n^3)
* @param nums
* @param k
* @return
*/
public int subarraySum01(int[] nums, int k) {
int len = nums.length;
int count = 0;
for (int left = 0; left < len; left++) {
for (int right = left; right < len; right++) {
int sum = 0;
for (int i = left; i <= right; i++) {
sum += nums[i];
}
if (sum == k) {
count++;
}
}
}
return count;
}
/**
* 1. 欠考虑情况
* ① 单个元素作为一个子数组;
* ② 所有元素值都相同的情况;
*
* 时间复杂:O (n^2)
*
* @param nums
* @param k
* @return
*/
public int subarraySum02(int[] nums, int k) {
int length = nums.length;
int count = 0;
// 0, 0, 0, 0
// l
// r
for (int left = 0; left < length; left++) {
int right = left + 1;
int sums = nums[left];
if (sums == k) {
count++;
}
while (right < length) {
sums += nums[right++];
if (sums == k) {
count++;
}
}
}
return count;
}
/**
* 前缀和
*
*
* @param nums
* @param k
* @return
*/
public int subarraySum03(int[] nums, int k) {
int length = nums.length;
int[] preSum = new int[length + 1];
preSum[0] = 0;
for (int i = 0; i < length; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
// 1, 2, 3, 4
// 0 1 3 6 10
// l
// r
int count = 0;
for (int left = 0; left < length; left++) {
int right = left + 1;
while (right <= length) {
if (preSum[right++] - preSum[left] == k) {
count++;
}
}
}
return count;
}
/**
*
* O (n)
* 前缀和 + 哈希表
*
* @param nums
* @param k
* @return
*/
public int subarraySum04(int[] nums, int k) {
Map preSumFreq = new HashMap<>();
preSumFreq.put(0, 1);
int preSum = 0;
int count = 0;
for (int num : nums) {
preSum += num;
if (preSumFreq.containsKey(preSum - k)) {
count += preSumFreq.get(preSum - k);
}
preSumFreq.put(preSum, preSumFreq.getOrDefault(preSum, 0) + 1);
}
return count;
}
public static void main(String[] args) {
// 1. 可以进行排序不?
SubarraySumEqualsK subarraySumEqualsK = new SubarraySumEqualsK();
//int[] nums = {0,0,0,0,0,0,0,0,0,0};
int[] nums = {1, 2, 3, 4};
System.out.println(subarraySumEqualsK.subarraySum04(nums, 5));
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/ThreeSum.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author LuoHaiYang
*
* url: https://leetcode-cn.com/problems/3sum/
*
*/
public class ThreeSum {
public static void main(String[] args) {
int[] nums = {3, 0, -2, -1, 1, 2};
threeSum(nums);
}
/**
* nums = [-1, 0, 1, 2, -1, -4]
*
* a + b + c = 0
*
* [
* [-1, 0, 1],
* [-1, -1, 2]
* ]
*
* @param nums
* @return
*/
public static List> threeSum(int[] nums) {
/**
*
* 解法一
* 1. 如何解决元素重复问题?
* 答:解决重复的关键就是对素组进行排序;
*
* 结果对索引没有要求,为什么不先进行排序呢??
* ① 对结果进行排序;
* 排序后固定一个数nums[i],再使用左右指针指向nums[i]后面的“两端”,值分别为nums[L]和nums[R],计算三个数的sum判断是否满足为0
* - 如果满足则添加进结果集
* - 由于排序的原因,所以如果nums[i]的值大于0,则三者之和必不=0
*
*
*
*/
List> ans = new ArrayList();
int len = nums.length;
//合法性判断
if (nums == null || len < 3) {
return ans;
}
//如果手撕算法不能使用工具类进行排序,则要可以使用QuickSort来进行排序;
// 排序
Arrays.sort(nums);
for (int i = 0; i < len; i++) {
// 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if (nums[i] > 0) {
break;
}
// 去重
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int L = i + 1;
int R = len - 1;
while (L < R) {
int sum = nums[i] + nums[L] + nums[R];
if (sum == 0) {
ans.add(Arrays.asList(nums[i], nums[L], nums[R]));
while (L < R && nums[L] == nums[L + 1]) {
L++; // 去重
}
while (L < R && nums[R] == nums[R - 1]) {
R--; // 去重
}
L++;
R--;
} else if (sum < 0) {
L++;
} else if (sum > 0) {
R--;
}
}
}
//return ans;
//========================================================= 结题方法分割线 ===============================================================
/**
*
*/
if (nums.length < 3) {
return Collections.emptyList();
}
List> res = new ArrayList<>();
int minValue = Integer.MAX_VALUE;
int maxValue = Integer.MIN_VALUE;
int negSize = 0;
int posSize = 0;
int zeroSize = 0;
for (int v : nums) {
if (v < minValue) {
minValue = v;
}
if (v > maxValue) {
maxValue = v;
}
if (v > 0) {
posSize++;
} else if (v < 0) {
negSize++;
} else {
zeroSize++;
}
}
if (zeroSize >= 3) {
res.add(Arrays.asList(0, 0, 0));
}
if (negSize == 0 || posSize == 0) {
return res;
}
if (minValue * 2 + maxValue > 0) {
maxValue = -minValue * 2;
} else if (maxValue * 2 + minValue < 0) {
minValue = -maxValue * 2;
}
int[] map = new int[maxValue - minValue + 1];
int[] negs = new int[negSize];
int[] poses = new int[posSize];
negSize = 0;
posSize = 0;
for (int v : nums) {
if (v >= minValue && v <= maxValue) {
if (map[v - minValue]++ == 0) {
if (v > 0) {
poses[posSize++] = v;
} else if (v < 0) {
negs[negSize++] = v;
}
}
}
}
Arrays.sort(poses, 0, posSize);
Arrays.sort(negs, 0, negSize);
int basej = 0;
for (int i = negSize - 1; i >= 0; i--) {
int nv = negs[i];
int minp = (-nv) >>> 1;
while (basej < posSize && poses[basej] < minp) {
basej++;
}
for (int j = basej; j < posSize; j++) {
int pv = poses[j];
int cv = 0 - nv - pv;
if (cv >= nv && cv <= pv) {
if (cv == nv) {
if (map[nv - minValue] > 1) {
res.add(Arrays.asList(nv, nv, pv));
}
} else if (cv == pv) {
if (map[pv - minValue] > 1) {
res.add(Arrays.asList(nv, pv, pv));
}
} else {
if (map[cv - minValue] > 0) {
res.add(Arrays.asList(nv, cv, pv));
}
}
} else if (cv < nv) {
break;
}
}
}
return res;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TopKFrequentElements.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.*;
/**
*
* 前K个高频元素
*
* url:https://leetcode-cn.com/problems/top-k-frequent-elements/
*
* @author LuoHaiYang
*/
public class TopKFrequentElements {
/**
*
* 桶排序
*
*/
public int[] topKFrequent(int[] nums, int k) {
List res = new ArrayList<>();
if (nums == null || nums.length < 2) {
return nums;
}
Map count = new LinkedHashMap<>();
int n = nums.length;
for (int i = 0; i < n; i++) {
if (count.containsKey(nums[i])) {
count.put(nums[i], count.get(nums[i]) + 1);
} else {
count.put(nums[i], 1);
}
}
List[] list = new List[nums.length];
for (int key : count.keySet()) {
// 让频率作为下标
int i = count.get(key);
if (list[i] == null) {
list[i] = new ArrayList<>();
}
// key表示的是元素
list[i].add(key);
}
for (int i = list.length - 1; i >= 0 && res.size() < k; i--) {
if (list[i] == null) {
continue;
}
res.addAll(list[i]);
}
int[] result = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
result[i] = res.get(i);
}
return result;
}
public static void main(String[] args) {
TopKFrequentElements topKFrequentElements = new TopKFrequentElements();
//int[] test = {1,1,1,2,2,3};
int[] test = {3,0,1,0};
topKFrequentElements.topKFrequent(test,1);
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSum.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
import java.util.HashMap;
import java.util.Map;
/**
* @author LuoHaiYang
*
* url: https://leetcode-cn.com/problems/two-sum/
*
*/
public class TwoSum {
/**
*
* nums = [2, 7, 11, 15], target = 9
*
* 返回: [0, 1]
*
*
* @param nums
* @param target
* @return
*/
public static int[] twoSum(int[] nums, int target) {
if (nums.length < 2) {
return nums;
}
/**
* 1. (原始)暴力解法:
*
* 时间换空间
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
*
*/
int[] result = {-1, -1};
for (int i = 0; i < nums.length; i++) {
result[0] = i;
int ret = target - nums[i];
for (int j = i + 1; j < nums.length; j++) {
if (ret == nums[j]) {
result[1] = j;
return result;
}
}
}
//return nums;
//========================================================= 结题方法分割线 ===============================================================
/**
* 2. 暴力解法:
*
* 空间换时间
* 时间复杂度:O(n)
* 空间复杂度:O(n)
*
* 这里为什么要用数组索引作为map的value呢?
* 这是为了方便当匹配到 target - nums[i]时取到对应
* 元素的索引。
*
*
* 总结: 对于要利用空间换时间的算法,多数都利用哈希表来实现。
*
*
*/
Map map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int ret = target - nums[i];
if (map.containsKey(ret)) {
return new int[] {map.get(nums[i]), i};
}
map.put(nums[i], i);
}
return null;
}
public static void main(String[] args) {
int[] nums = {3, 2, 4};
int target = 6;
System.out.println(twoSum(nums, target));
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/TwoSumII.java
================================================
package com.bruis.algorithminjava.algorithm.leetcode.array;
/**
* 167:
*
* https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/description/?utm_source=LCUS&utm_medium=ip_redirect_q_uns&utm_campaign=transfer2china
*
* 思路:指针碰撞
*
* @author LuoHaiYang
*/
public class TwoSumII {
public int[] twoSum(int[] numbers, int target) {
if (numbers.length < 2) {
return numbers;
}
int left = 0, right = numbers.length - 1;
while (left <= right) {
int result = numbers[left] + numbers[right];
if (result == target) {
int[] res = {left + 1, right + 1};
return res;
} else if (result > target) {
right --;
} else {
left ++;
}
}
return numbers;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/BinarySearch.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
*
* 二分查找法
*
* @author LuoHaiYang
*/
public class BinarySearch {
public static int binarySearch(int[] arr, int n, int target) {
// 在 [left, right]范围里寻找target
int left = 0, right = n - 1;
while (left <= right) {
int mid = (right + left) / 2;
int nums = arr[mid];
if (nums == target) {
return mid;
} else if (nums > target) {
left = mid + 1;
} else {
// nums < target
right = mid - 1;
}
}
return -1;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/BubbleSort.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
* @author LuoHaiYang
*/
public class BubbleSort {
// 方式1
public static void sort(int[] arr) {
int n = arr.length;
boolean swapped = false;
do {
swapped = false;
for (int i = 1; i < n; i++) {
if (arr[i - 1] > arr[i]) {
swap(arr, i - 1, i);
swapped = true;
}
}
} while(swapped);
}
// 方式2
public static void sort2(int[] arr) {
int n = arr.length;
if (n <= 1) {
return;
}
// 使用newn来进行优化
int newn;
do {
newn = 0;
for (int i = 1; i < n; i++) {
if (arr[i - 1] > arr[i]) {
swap(arr, i - 1, i);
// 记录当前排序最后一次交换的位置,在此之后的元素在下一轮扫描中均不考虑
newn = i;
}
}
n = newn;
} while (newn > 0);
}
// 方式3
public static void sort3(int[] arr) {
int n = arr.length;
if (n <= 1) {
return;
}
for (int i = 0; i < n; i++) {
boolean flag = false;
// n - i - 1 表示每轮排序都会有一个最大元素冒泡到最大位置,因而每轮排序都会少一个遍历的元素
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] < arr[j + 1]) {
swap(arr, j, j + 1);
flag = true;
}
}
// 此轮排序没有数据交换,则退出排序
if (!flag) {
break;
}
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* 桶排序
*
* @author LuoHaiYang
*/
public class BucketSort {
/* 排序原理:
桶排序本质就是空间换时间:时间复杂度为:O(n)
顺序从待排数组中取出数字,首先6被取出,然后把6入6号桶,这个过程类似这样:空桶[ 待排数组[ 0 ] ] = 待排数组[ 0 ]
[6 2 4 1 5 9] 待排数组
[0 0 0 0 0 0 6 0 0 0] 空桶
[0 1 2 3 4 5 6 7 8 9] 桶编号(实际不存在)
顺序从待排数组中取出下一个数字,此时2被取出,将其放入2号桶,是几就放几号桶
[6 2 4 1 5 9] 待排数组
[0 0 2 0 0 0 6 0 0 0] 空桶
[0 1 2 3 4 5 6 7 8 9] 桶编号(实际不存在)
3,4,5,6省略,过程一样,全部入桶后变成下边这样
[6 2 4 1 5 9] 待排数组
[0 1 2 0 4 5 6 0 0 9] 空桶
[0 1 2 3 4 5 6 7 8 9] 桶编号(实际不存在)
*/
private int range = 0;
public BucketSort(int range) {
this.range = range;
}
public int[] doSort(int[] arr) {
// 集合数组
List[] aux = new LinkedList[range];
for (int i = 0; i < aux.length; i++) {
aux[i] = new LinkedList<>();
}
for (int i = 0; i < arr.length; i++) {
aux[arr[i]].add(arr[i]);
}
for (int i = 0, j = 0; i < aux.length && j < arr.length; i++) {
for (int v : aux[i]) {
arr[j] = v;
j++;
}
}
return arr;
}
public static void main(String[] args) {
BucketSort bucketSort = new BucketSort(10);
int[] sort = bucketSort.doSort(new int[]{4, 1, 3, 2, 20, 6, 9, 9, 21, 19});
System.out.println(Arrays.toString(sort));
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/Heap.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
* 此堆索引从0开始
*
* @Description
* @Author luohaiyang
* @Date 2022/4/20
*/
public class Heap {
private int[] data;
private int count;
private int capacity;
/**
*
*
*
* a
1
b c
2 3
d e f g
4 5 6 7
q w r x
8 9 10 11
*
*
*
*
*/
/**
* 初始化堆
* @param capacity
*/
public Heap(int capacity) {
this.capacity = capacity;
data = new int[capacity+1];
count = 0;
}
public Heap(int[] data, int capacity) {
this.data = data;
heapify(capacity);
}
/**
* 新增一个元素
* @param value
*/
public void insert(int value) {
if (count + 1 > capacity) {
// 抛异常
}
data[++count] = value;
shiftUp(count);
}
/**
* 获取堆顶值
* @return
*/
public int extractMax() {
if (count < 1) {
// 抛异常
}
int max = data[1];
swap(1, count--);
shiftDown(1);
return max;
}
/**
* 堆化
*/
public void heapify(int k) {
while (k/2 >= 1) {
shiftDown(k/2);
k--;
}
}
public int size() {
return count;
}
public boolean isEmpty() {
return count == 0;
}
/**
* 上浮操作
* @param k
*/
private void shiftUp(int k) {
while (k > 1 && data[k] > data[k/2]) {
swap(k, k/2);
k /= 2;
}
}
/**
* 下层操作
* @param k
*/
private void shiftDown(int k) {
while (count >= k * 2) {
int j = k * 2;
if (j+1 <= count && data[j] < data[j+1]) j++;
if (data[k] >= data[j]) break;
swap(k, j);
k = j;
}
}
private void swap(int a, int b) {
int tmp = data[a];
data[a] = data[b];
data[b] = tmp;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort01.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
import java.util.Random;
/**
*
* 借助辅助空间进行堆排序
*
* @author LuoHaiYang
*/
public class HeapSort01 {
/**
* 堆化完后并没有排序完成
* @param arr
*/
private static void heapify(int[] arr) {
int n = arr.length;
for (int i = n/2; i > 0; i--) {
shiftDown(i, n, arr);
}
}
/**
* 获取最大堆中堆顶元素
*/
private static int extractMax(int[] arr) {
int n = arr.length;
int max = arr[0];
swap(arr, 0, --n);
// 让最后一个元素置0
arr[n] = 0;
shiftDown(0, n, arr);
return max;
}
/**
* 下沉操作
* @param k
*/
private static void shiftDown(int k, int n, int[] arr) {
while (k * 2 + 1 < n) {
// 左子树节点
int j = k * 2 + 1;
if (j + 1 < n && arr[j + 1] > arr[j]) {
j++;
}
if (arr[k] >= arr[j]) {
break;
}
swap(arr, k, j);
k = j;
}
}
/**
* 上浮操作
* @param k
*/
private void shiftUp(int k, int[] arr) {
while (k > 0 && arr[(k-1)/ 2] < arr[k]) {
swap(arr, (k-1)/2, k);
k = (k-1)/2;
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static int[] sort(int[] arr) {
int n = arr.length;
heapify(arr);
int[] result = new int[n];
for (int i = 0; i < n; i++) {
result[i] = extractMax(arr);
}
return result;
}
public static void main(String[] args) {
int n = 100;
int[] test = new int[n];
Random random = new Random();
for (int i = 0; i < n; i++) {
test[i] = random.nextInt(1000);
}
sort(test);
// 测试
for (int i = 1; i < n; i++) {
if (test[i-1] < test[i]) {
System.out.println("Error!");
}
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/HeapSort02.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
*
* 原地堆排序! 不需要额外的空间
*
* 这里构造出来的是一个最小堆
*
* @author LuoHaiYang
*/
public class HeapSort02 {
public static void sort(int[] arr) {
int n = arr.length;
// 注意,此时我们的堆是从0开始索引的
// 从(最后一个元素的索引-1)/2开始
// 最后一个元素的索引 = n-1
// 其实这里 i = (n-1) 也行
for (int i = (n - 1 - 1) / 2; i >= 0; i--) {
siftDown2(arr, n, i);
}
// [a.....v,k]
// [.......]k
// [.....] ba
for (int i = n-1; i > 0; i--) {
// 由于上面执行过下沉操作,所以已经是最大堆(但没有排序完)。所以此时swap就将最大值替换到数组末尾。
swap(arr, 0, i);
// 由于siftDown中是判断 2*k+1 < n ,所以就是对n-1进行下沉操作;
siftDown2(arr, i, 0);
}
}
// 下浮
public static void siftDown(int[] arr, int n, int k) {
while (2 * k + 1 < n) {
int j = 2 * k + 1;
if (j + 1 < n && arr[j+1] > arr[j]) {
j += 1;
}
if (arr[k] >= arr[j]) {
break;
}
swap(arr, k, j);
k = j;
}
}
/**
* 优化下沉过程, 不适用swap交换,通过赋值来代替。
*
* @param arr
* @param n
* @param k
*/
private static void siftDown2(int[] arr, int n, int k) {
int e = arr[k];
while (2 * k + 1 < n) {
int j = 2 * k + 1;
if (j + 1 < n && arr[j + 1] > arr[j]) {
j++;
}
if (e >= arr[j]) {
break;
}
// 此时说明arr[j] > arr[k]; 所以让大值上浮;
arr[k] = arr[j];
k = j;
}
// 将最小元素替换到k的位置
arr[k] = e;
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
/*
int n = 100;
int[] test = new int[n];
Random random = new Random();
for (int i = 0; i < n; i++) {
test[i] = random.nextInt(1000);
}
*/
int n = 10;
int[] test = {10, 41, 30, 28, 16, 22, 13, 19, 17, 15};
sort(test);
for (int i = 1; i < n; i++) {
if (test[i-1] > test[i]) {
throw new IllegalArgumentException("Error!");
}
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/InsertionSort.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
* @author LuoHaiYang
*/
public class InsertionSort {
// 方式1
public static void sort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n; i++) {
for (int j = i; j > 0; j--) {
// 注意这里j-1没有越界,因为j > 0进行了判断
if (arr[j] < arr[j-1]) {
swap(arr, j, j-1);
} else {
break;
}
}
}
}
// 方式2
public static void sort2(int[] arr) {
int n = arr.length;
for (int i = 0; i < n; i++) {
for (int j = i; j > 0 && arr[j] < arr[j-1]; j--) {
// 注意这里j-1没有越界,因为j > 0进行了判断
swap(arr, j, j-1);
}
}
}
// 方式3,优化版
public static void sort3(int[] arr) {
int n = arr.length;
for (int i = 0; i < n; i++) {
// 获取需要比较的元素
int e = arr[i];
int j = i;
for (; j > 0 && e < arr[j-1] ; j--) {
// 如果满足条件,则前一位元素复制给后一位元素
arr[j] = arr[j-1];
}
// 跳出循环,则将需要比较的e元素替换到j位置,j位置即最终停留的位置
arr[j] = e;
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int [] arr = {6,2,1,5,4,3};
sort2(arr);
for (int n : arr) {
System.out.println(n);
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/MergeSort.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
import java.util.Arrays;
/**
*
* 归并排序
*
* @author LuoHaiYang
*/
public class MergeSort {
/**
*
* 将arr[left...mid]和arr[mid+1...right]两部分进行归并
*
* @param arr
* @param left
* @param mid
* @param right
*/
public static void merge(int[] arr, int left, int mid, int right) {
int[] aux = Arrays.copyOfRange(arr, left, right + 1);
// i表示左边;j表示右边;
int i = left, j = mid + 1;
// 从左left遍历到右right, 左闭又开
for (int k = left; k <= right; k++) {
// 如果左边指针大于mid,则表示左半边数据已经归并完毕
if (i > mid) {
// j-left计算出相对aux的位置
arr[k] = aux[j-left];
j++;
} else if (j > right) {
// j大于right值,则表示右半边数据已经归并完毕
arr[k] = aux[i-left];
i++;
} else if (aux[i-left] < aux[j-left]) {
arr[k] = aux[i-left];
i++;
} else {
arr[k] = aux[j-left];
j++;
}
}
}
/**
*
* 对[left, right]范围进行排序
*
* @param arr
* @param left
* @param right
*/
public static void sort(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int mid = (left + right) / 2;
sort(arr, left, mid);
sort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
public static void sort(int[] arr) {
int n = arr.length;
sort(arr, 0, n-1);
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/MergeSortAdvanced01.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
import java.util.Arrays;
/**
*
* 归并排序优化版本1
*
* @author LuoHaiYang
*/
public class MergeSortAdvanced01 {
public static void merge(int[] arr, int left, int mid, int right) {
int[] aux = Arrays.copyOfRange(arr, left, right + 1);
int i = left, j = mid + 1;
for (int k = left; k <= right; k++) {
if (i > mid) {
arr[k] = aux[j-left];
j++;
} else if (j > right) {
arr[k] = aux[i-left];
i++;
} else if (aux[i-left] < aux[j-left]) {
arr[k] = aux[i-left];
i++;
} else {
arr[k] = aux[j-left];
j++;
}
}
}
public static void sort(int[] arr, int left, int right) {
// 优化2: 对于小规模数组, 使用插入排序
if (right - left <= 15) {
InsertionSort.sort(arr);
return;
}
int mid = (left + right) / 2;
sort(arr, left, mid);
sort(arr, mid + 1, right);
// 优化1: 对于arr[mid] <= arr[mid+1]的情况,不进行merge
// 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失
if (arr[mid] > arr[mid+1]) {
merge(arr, left, mid, right);
}
}
public static void sort(int[] arr) {
int n = arr.length;
sort(arr, 0, n-1);
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/MergeSortBU.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
import java.util.Arrays;
/**
*
* 归并排序(自底向上)
*
* @author LuoHaiYang
*/
public class MergeSortBU {
private static void merge(int[] arr, int left, int mid, int right) {
int[] aux = Arrays.copyOfRange(arr, left, right + 1);
int i = left, j = right + 1;
for (int k = 0; k <= right; k++) {
if (i > mid) {
arr[k] = aux[j - left];
j++;
} else if (j > right) {
arr[k] = aux[i - left];
i++;
} else if (aux[i - left] > aux[j - left]) {
arr[k] = aux[j - left];
j++;
} else {
arr[k] = aux[i - left];
i++;
}
}
}
// [a, b, c, d, e, f, g, h, i]
// [a,b] [c,d] [e,f] [g,h]
public static void sort(int[] arr) {
int n = arr.length;
for (int sz = 1; sz < n; sz *= 2) {
for (int i = 0; i < n - sz; i += sz + sz) {
merge(arr, i, i+sz-1, Math.min(i+sz+sz-1, n-1));
}
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
*
* 快速排序
*
* @author LuoHaiYang
*/
public class QuickSort {
/**
* 对arr[left...right]部分进行partition操作
* 返回p, 使得arr[left...p-1] < arr[p] ; arr[p+1...right] > arr[p]
*
* @param arr
* @param left
* @param right
* @return
*/
private static int partition(int[] arr, int left, int right) {
int p = arr[left];
// arr[left+1...j] < p; arr[j+1...i) > p
int j = left;
for (int i = left + 1; i <= right; i++) {
if (arr[i] < p) {
j++;
swap(arr, j, i);
}
}
swap(arr, left, j);
return j;
}
private static void sort(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int p = partition(arr, left, right);
sort(arr, left, p-1);
sort(arr, p+1, right);
}
public static void sort(int[] arr) {
int n = arr.length;
sort(arr, 0, n-1);
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
* 快速排序的优化
*
* 对于近乎有序的数组,快速排序会退化为O(n^2)。
*
* @author LuoHaiYang
*/
public class QuickSort2 {
/**
* 对arr[left...right]部分进行partition操作
* 返回p, 使得arr[left...p-1] < arr[p] ; arr[p+1...right] > arr[p]
*
* @param arr
* @param left
* @param right
* @return
*/
private static int partition(int[] arr, int left, int right) {
//int p = arr[left];
// ===================================== 优化2 =====================================
// 避免快排退化为O(n^2)
swap(arr, left, (int)Math.random()*(right - left + 1) + left);
int p = arr[left];
// arr[left+1...j] < p; arr[j+1...i) > p
int j = left;
for (int i = left + 1; i <= right; i++) {
if (arr[i] < p) {
j++;
swap(arr, j, i);
}
}
swap(arr, left, j);
return j;
}
private static void sort(int[] arr, int left, int right) {
// ===================================== 优化1 =====================================
// 如果左右数值小于15,则通过插入排序来进行排序
if (right - left <= 15) {
InsertionSort.sort(arr);
return;
}
int p = partition(arr, left, right);
sort(arr, left, p-1);
sort(arr, p+1, right);
}
public static void sort(int[] arr) {
int n = arr.length;
sort(arr, 0, n-1);
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2Ways.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
*
* 双路快排
*
* @author LuoHaiYang
*/
public class QuickSort2Ways {
private static int partition(int[] arr, int left, int right) {
swap(arr, left, (int)Math.random()*(right - left + 1) + left);
int p = arr[left], i = left + 1, j = right;
while(true) {
/**
* 这里arr[i] < p 和 arr[j] > p 是为了避免出现 arr[i] == p 和 arr[j] == p的情况。
* 如果arr[i] == p,则直接进行了i++了,则数组的p会变得极度不平衡,即 所有小于等于p的值都分在了左边,
* 这种情况下,快速排序的平均时间复杂度会退化成:O(n^2)
*
*/
while(i <= right && arr[i] < p) {
i++;
}
while(j >= 0 && arr[j] > p) {
j--;
}
if (i > j) {
break;
}
swap(arr, i++, j--);
}
swap(arr, left, j);
return j;
}
private static void sort(int[] arr, int left, int right) {
if (right - left <= 15) {
InsertionSort.sort(arr);
return;
}
int p = partition(arr, left, right);
sort(arr, left, p - 1);
sort(arr, p + 1, right);
}
public static void sort(int[] arr) {
int n = arr.length;
sort(arr, 0, n - 1);
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort3Ways.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
*
* 三路快排
*
* @author LuoHaiYang
*/
public class QuickSort3Ways {
private static void sort(int[] arr, int left, int right) {
if (right - left <= 15) {
InsertionSort.sort(arr);
return;
}
// 增加随机值,防止快排退化为O(n^2)
swap(arr,left, (int)Math.random()*(right - left - 1) + left);
int p = arr[left];
// [p...................................................right]
// p
// lt
// i
// gt
// arr[left+1...lt] < p arr[lt+1...i) = p arr[gt...right] > p
int lt = left, gt = right + 1, i = left + 1;
while ( i < gt) {
if (arr[i] < p) {
swap(arr, lt+1, i);
i++;
lt++;
} else if (arr[i] > p) {
swap(arr, i, gt-1);
gt--;
} else {// arr[i] == v
i++;
}
}
swap(arr, left, lt);
// 继续对[left,lt]进行排序
sort(arr, left, lt-1);
// 继续对[gt, right]进行排序
sort(arr, gt, right);
}
public static void sort(int[] arr) {
int n = arr.length;
sort(arr, 0, n-1);
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/sort/ShellSort.java
================================================
package com.bruis.algorithminjava.algorithm.sort;
/**
*
* 希尔排序
*
* @author LuoHaiYang
*/
public class ShellSort {
public static void sort(int[] arr) {
int n = arr.length;
int h = 1;
while (h < n / 3) {
h = 3 * h + 1;
}
while (h >= 1) {
for (int i = h; i < n; i++) {
int e = arr[i];
int j = i;
for (; j >= h && e < arr[j-h]; j -= h) {
arr[j] = arr[j-h];
}
arr[j] = e;
}
h /= 3;
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/algorithm/stack/MinStack.java
================================================
package com.bruis.algorithminjava.algorithm.stack;
import java.util.Stack;
/**
* @author LuoHaiYang
*
* @Date 2020.05.13
*
* url: https://leetcode-cn.com/problems/min-stack/
*
*
*/
public class MinStack {
/**
* 问题:
* 1. 用什么基础数据结构来存储数据? 普遍解法都是通过已有数据结构stack来解决
* 2. 如何自己实现一个栈结构?
*/
/** initialize your data structure here. */
private Stack stack;
private Stack minStack;
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
public void push(int x) {
stack.push(x);
if (!minStack.isEmpty()) {
int top = minStack.peek();
//小于的时候才入栈
if (x <= top) {
minStack.push(x);
}
}else{
minStack.push(x);
}
}
public void pop() {
int pop = stack.pop();
int top = minStack.peek();
//等于的时候再出栈
if (pop == top) {
minStack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/array/MyArray.java
================================================
package com.bruis.algorithminjava.datastructures.array;
/**
* @author LuoHaiYang
*/
public class MyArray {
//存储的数据
private E[] data;
//数组大小,数组容量大小不一定等于数组实际大小
private int size;
//设置数组大小
public MyArray(int capacity) {
data = (E[])new Object[capacity];
this.size = capacity;
}
public MyArray() {
this(10);
}
//数组容量大小
public int getCapacity() {
return this.data.length;
}
//数组元素大小
public int getSize() {
return this.size;
}
public boolean isEmpty() {
return size == 0;
}
//在index索引位置插入新元素
public void insert(int index, E value) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("添加失败,数组索引越界!");
}
//如果数组容量不足,则扩容两倍
if (size == data.length) {
resize(2 * size);
}
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = value;
size ++;
}
public E delete(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("删除失败,数组索引越界!");
}
E delValue = data[index];
for (int i = index; i < size - 1; i++) {
data[i] = data[i +1];
}
size --;
//gc
data[size] = null;
return delValue;
}
public void update(int index, E value) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("删除失败,数组索引越界!");
}
data[index] = value;
}
// 向所有元素后添加一个元素
public void addLast(E e) {
insert(size, e);
}
// 向所有元素前添加一个元素
public void addFirst(E e) {
insert(0, e);
}
public E get(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("删除失败,数组索引越界!");
}
return data[index];
}
// 获取末尾元素
public E getLast() {
return get(size - 1);
}
// 获取首部元素
public E getFirst() {
return get(0);
}
public boolean contains(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return true;
}
}
return false;
}
// 查看数组中元素e所在的索引,如果不存在则返回-1
public int find(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
public E remove(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("删除失败,数组索引越界!");
}
E del = data[index];
for (int i = index + 1; i < size; i++) {
data[i-1] = data[i];
}
size--;
data[size] = null;
if (size == data.length / 4 && data.length / 2 != 0) {
resize(data.length / 2);
}
return del;
}
// 从数组中删除第一个元素, 返回删除的元素
public E removeFirst(){
return remove(0);
}
// 从数组中删除最后一个元素, 返回删除的元素
public E removeLast(){
return remove(size - 1);
}
// 从数组中删除元素e
public void removeElement(E e){
int index = find(e);
if(index != -1){
remove(index);
}
}
public void resize(int newSize) {
E[] newData = (E[])new Object[newSize];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
private void printData(E[] data, int size) {
System.out.println();
for (int j = 0; j < size; j++) {
System.out.print(data[j]);
if (j != size) {
System.out.print(",");
} else {
System.out.println();
}
}
}
public static void main(String[] args) {
int size = 5;
MyArray myArray = new MyArray(size);
//增加
for (int i = 0; i < 3; i++) {
myArray.insert(i, i);
}
myArray.printData(myArray.data, myArray.size);
//删除
System.out.println(myArray.delete(1));
myArray.printData(myArray.data, myArray.size);
//修改
myArray.update(1, 666);
myArray.printData(myArray.data, myArray.size);
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/heap/IndexMapHeap.java
================================================
package com.bruis.algorithminjava.datastructures.heap;
import java.util.Arrays;
import java.util.Random;
/**
*
* 索引堆
*
* @author LuoHaiYang
*/
public class IndexMapHeap {
/**
* 存储数据的数组
*/
private int[] arr;
/**
* index元素值就是arr的索引
*/
private int[] index;
/**
* 数组存储容量大小
*/
private int count;
/**
* 容量
*/
private int capacity;
public IndexMapHeap(int capacity) {
this.capacity = capacity;
this.count = 0;
// 让索引从0开始
arr = new int[capacity + 1];
// 让索引从0开始
index = new int[capacity + 1];
}
public boolean isEmpty() {
return count == 0;
}
public int size() {
return count;
}
/**
* 插入新元素
* @param i
* @param item
*/
public void insert(int i, int item) {
if (i + 1 > capacity) {
throw new IllegalArgumentException("容量已满, 插入失败");
}
arr[++i] = item;
index[++count] = i;
shiftUp(count);
}
/**
* 获取最大索引堆中所以为i的元素
* @param i
* @return
*/
public int getItem(int i) {
if (i < 0 && i + 1 > capacity) {
throw new IllegalArgumentException("错误!索引越界.");
}
return arr[i+1];
}
/**
* 获取索引堆中堆顶的元素(注意堆中元素是arr的索引,即index数组的元素)
* @return
*/
public int getMaxIndex() {
if (count < 1) {
throw new IllegalArgumentException("异常!堆中没有元素!");
}
// 由于索引堆中元素也是从1开始,所以需要-1,从0开始。
return index[1] - 1;
}
/**
* 获取最大索引堆中堆顶元素的值,即索引堆中存储的最大数据
* @return
*/
public int extractMax() {
if (count < 1) {
throw new IllegalArgumentException("错误!索引堆中不存在元素");
}
int ret = arr[index[1]];
// 取出堆顶元素数据后,需要把最大元素和index末尾元素进行替换,然后做下沉操作
swap(index, 1, count);
count--;
shiftDown(1);
return ret;
}
/**
* 获取最大索引堆中堆顶的索引
* @return
*/
public int extractMaxIndex() {
if (count < 1) {
throw new IllegalArgumentException("错误!索引堆中不存在元素");
}
int ret = index[1] - 1;
swap(index, 1, count);
count--;
shiftDown(1);
return ret;
}
// ============================= 上浮操作 =============================
/**
* 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
* @param k
*/
private void shiftUp(int k) {
// 堆顶元素则直接跳过
while (k > 1 && arr[index[k/2]] < arr[index[k]]) {
swap(index, k, k/2);
k /= 2;
}
}
// ============================= 下沉操作 =============================
/**
* 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
*
* 由于是由1开始计算索引,所以左子树为 2*k
*
* @param k
*/
private void shiftDown(int k) {
// 如果左子树所以 <= 元素总数
while ( 2 * k <= count) {
int j = 2 * k;
if (j + 1 <= count && arr[index[j+1]] > arr[index[j]]) {
j++;
}
if (arr[index[k]] >= arr[index[j]]) {
break;
}
// 更换索引值
swap(index, k, j);
k = j;
}
}
// ============================= 更新堆元素优先级 =============================
/**
*
*
*
* @param i
* @param item
*/
public void change(int i, int item) {
i++;
// 将所有堆中索引为i的元素修改为item
arr[i] = item;
// 由于直接在i位置修改为新元素;
// 所以需要查找出 index[j] = i的位置,即arr[index[j]] = item;
// 然后上浮和下沉(先后顺序不影响)
for (int j = 1; j <= count; j++) {
if (index[j] == i) {
shiftUp(j);
shiftDown(j);
return;
}
}
}
private void swap(int[] arr, int i, int k) {
int tmp = arr[i];
arr[i] = arr[k];
arr[k] = tmp;
}
// ============================= 更新堆元素优先级 =============================
public boolean testIndexes() {
int[] copyIndex = new int[count + 1];
for (int i = 0; i <= count; i++) {
copyIndex[i] = index[i];
}
copyIndex[0] = 0;
Arrays.sort(copyIndex);
for (int i = 2; i <= count; i++) {
if (copyIndex[i-1] + 1 != copyIndex[i]) {
System.out.println("错误,索引堆排序错误!");
break;
}
}
return true;
}
public void testSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
if (arr[i-1] < arr[i]) {
System.out.println("索引堆排序失败!");
}
}
}
public static void main(String[] args) {
int n = 10;
IndexMapHeap indexMapHeap = new IndexMapHeap(n);
Random random = new Random();
for (int i = 0; i < n; i++) {
// insert中仅仅一个shiftUp操作是不能保证索引堆数据的排好序了
indexMapHeap.insert(i,random.nextInt(1000));
}
// 判断索引堆索引是否是连续
System.out.println(indexMapHeap.testIndexes());
int[] result = new int[n];
for (int i = 0; i < n; i++) {
result[i] = indexMapHeap.extractMax();
}
indexMapHeap.testSort(result);
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/heap/MaxHeap.java
================================================
package com.bruis.algorithminjava.datastructures.heap;
import java.util.Random;
/**
* @author LuoHaiYang
*/
public class MaxHeap {
/**
* 注意,由于数组元素默认值为0,所以堆中元素不可为0
*/
private int[] data;
/**
* 记录数组中元素个数
*/
private int size;
/**
* 数组容量(初始化大小)
*/
private int capacity;
public MaxHeap(int capacity) {
data = new int[capacity];
this.capacity = capacity;
size = 0;
}
public MaxHeap() {
data = new int[10];
capacity = 10;
size = 0;
}
// ================================ heapify(二叉堆化) ========================
public MaxHeap(int[] data) {
int n = data.length;
this.data = new int[n+1];
capacity = n;
for (int i = 0; i < n; i++) {
this.data[i+1] = data[i];
}
size = n;
// 这里需要注意,size / 2 得到的索引是二叉堆中最后一个非叶子节点。
// 注意!!! 这里size / 2 是因为 data 从1开始的,所以最后一个非叶子节点为:size / 2
// 如果是从0开始,则:size - 1
for (int i = size / 2; i > 0; i++) {
siftDown(i);
}
}
/**
* 返回堆中真实存在元素个数
* @return
*/
public int size() {
return size;
}
/**
* 返回堆中是否为空
* @return
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 返回index索引其父亲节点
* @param index
* @return
*/
private int parent(int index) {
if (index == 0) {
throw new IllegalArgumentException("index-0 doesn't have parent");
}
return (index - 1) / 2;
}
/**
* 返回index索引的左子节点
* @param index
* @return
*/
private int leftChild(int index) {
return index * 2 + 1;
}
/**
* 返回index索引的右子节点
* @param index
* @return
*/
private int rightChild(int index) {
return index * 2 + 2;
}
// ================================ 上浮 siftUp ========================
/**
* 向堆中添加元素
*/
public void add(int i) {
// 注意size和capacity的关系,判断是否容量已经满了
// 向数组最后一位添加新元素
data[size] = i;
siftUp(size++);
}
/**
* 上浮过程
* @param k
*/
private void siftUp(int k) {
// k 索引大于0,并且k索引元素值大于k父亲节点元素值
while (k > 0 && data[parent(k)] < data[k]) {
// k和parent(k)互换元素
swap(data, k, parent(k));
// 向上移动,让k为parent(k)再进行判断
k = parent(k);
}
}
// ================================ 下浮 siftDown ========================
/**
* 获取堆中最大元素
* @return
*/
public int findMax() {
if (size == 0) {
throw new IllegalArgumentException("Can't find Max value!");
}
return data[0];
}
/**
* 取出堆中最大元素
* @return
*/
public int extractMax() {
int max = findMax();
swap(data, 0, size - 1);
data[size - 1] = 0;
siftDown(0);
return max;
}
/**
* 下沉操作
* @param k
*/
private void siftDown(int k) {
// 左子节点比数组元素小,则表示有子节点
while (leftChild(k) < size()) {
int j = leftChild(k);
// 如果k的有右子节点
if (j + 1 < size() && data[j + 1] > data[j]) {
// 所以让j为右子节点
// j = rightChild(k); 同
j++;
}
// 此时data[k] 比leftChild和rightChild中的最大值都要大
if (data[k] > data[j]) {
break;
}
// leftChild和rightChild都比data[k]大,在互换之后,继续下一轮判断
swap(data, k, j);
// 互换位置,继续下一轮判断
k = j;
}
}
// ================================ 替换操作 ========================
private void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int n = 100;
MaxHeap maxHeap = new MaxHeap(n);
Random random = new Random();
for (int i = 0; i < n; i++) {
maxHeap.add(random.nextInt(1000));
}
int[] result = new int[n];
for (int i = 0; i < n; i++) {
result[i] = maxHeap.extractMax();
}
// 测试是否是顺序的
for (int j = 1; j < n; j++) {
if (result[j-1] < result[j]) {
throw new IllegalArgumentException("Error!");
}
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/queue/MyLoopQueue.java
================================================
package com.bruis.algorithminjava.datastructures.queue;
/**
* @author LuoHaiYang
*/
public class MyLoopQueue implements Queue {
private E[] data;
private int front, tail;
private int size;
public MyLoopQueue(int capacity) {
data = (E[])new Object[capacity + 1];
front = 0;
tail = 0;
size = 0;
}
public MyLoopQueue() {
this(10);
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return front == tail;
}
public int getCapacity() {
return data.length - 1;
}
/**
* 进队
*
* head tail
* [a, b, c, d, ..., z] <- addLast
*
* @param e
*/
@Override
public void enqueue(E e) {
if ((tail + 1) % data.length == front) {
resize(getCapacity() * 2);
}
data[tail] = e;
tail = (tail + 1) % data.length;
size ++;
}
@Override
public E dequeue() {
if (isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
}
E ret = data[front];
data[front] = null;
front = (front + 1) % data.length;
size--;
if (size == getCapacity() / 4 && getCapacity() / 2 != 0) {
resize(getCapacity() / 2);
}
return ret;
}
@Override
public E getFront() {
if(isEmpty()) {
throw new IllegalArgumentException("Queue is empty.");
}
return data[front];
}
private void resize(int newCapacity) {
E[] newData = (E[]) new Object[newCapacity + 1];
for (int i = 0; i < size; i++) {
newData[i] = data[(i + front) % data.length];
}
data = newData;
front = 0;
tail = size;
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append(String.format("Queue: size = %d , capacity = %d\n", size, getCapacity()));
res.append("front [");
for(int i = front ; i != tail ; i = (i + 1) % data.length){
res.append(data[i]);
if((i + 1) % data.length != tail)
res.append(", ");
}
res.append("] tail");
return res.toString();
}
public static void main(String[] args){
MyLoopQueue queue = new MyLoopQueue<>();
for(int i = 0 ; i < 12 ; i ++){
queue.enqueue(i);
System.out.println(queue);
if(i % 3 == 2){
queue.dequeue();
System.out.println(queue);
}
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/queue/MyQueue.java
================================================
package com.bruis.algorithminjava.datastructures.queue;
import com.bruis.algorithminjava.datastructures.array.MyArray;
/**
* @author LuoHaiYang
*/
public class MyQueue implements Queue {
private MyArray array;
public MyQueue(int capacity) {
array = new MyArray<>(capacity);
}
public MyQueue() {
array = new MyArray<>();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
/**
* head tail
* [a, b, c, d, ..., z] <- addLast
*
* @param e
*/
@Override
public void enqueue(E e) {
array.addLast(e);
}
/**
* head tail
* removeFirst <- [a, b, c, d, ..., z] <- addLast
*
*/
@Override
public E dequeue() {
return array.removeFirst();
}
@Override
public E getFront() {
return array.getFirst();
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("Queue: ");
res.append("front [");
for(int i = 0 ; i < array.getSize() ; i ++){
res.append(array.get(i));
if(i != array.getSize() - 1)
res.append(", ");
}
res.append("] tail");
return res.toString();
}
public static void main(String[] args) {
MyQueue queue = new MyQueue<>();
for(int i = 0 ; i < 10 ; i ++){
queue.enqueue(i);
System.out.println(queue);
if(i % 3 == 2){
queue.dequeue();
System.out.println(queue);
}
}
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/queue/Queue.java
================================================
package com.bruis.algorithminjava.datastructures.queue;
/**
* @author LuoHaiYang
*/
public interface Queue {
int getSize();
boolean isEmpty();
// 进队
void enqueue(E e);
// 移除队列
E dequeue();
// 获取队列首个元素
E getFront();
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/stack/MyStack.java
================================================
package com.bruis.algorithminjava.datastructures.stack;
import com.bruis.algorithminjava.datastructures.array.MyArray;
/**
* @author LuoHaiYang
*/
public class MyStack implements Stack {
private MyArray array;
public MyStack(int capacity){
array = new MyArray<>(capacity);
}
public MyStack(){
array = new MyArray<>();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
/**
* [a, b, c, d, ..., z] <- addLast
*
* @param e
*/
@Override
public void push(E e) {
// 由于栈是先进后出的数据结构,所以需要调用array的addLast
array.addLast(e);
}
/**
* [a, b, c, d, ..., z] -> removeLast
*
* @return
*/
@Override
public E pop() {
return array.removeLast();
}
@Override
public E peek() {
return array.getLast();
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("Stack: ");
res.append('[');
for(int i = 0 ; i < array.getSize() ; i ++){
res.append(array.get(i));
if(i != array.getSize() - 1) {
res.append(", ");
}
}
res.append("] top");
return res.toString();
}
public static void main(String[] args) {
MyStack stack = new MyStack<>();
for(int i = 0 ; i < 5 ; i ++){
stack.push(i);
System.out.println(stack);
}
stack.pop();
System.out.println(stack);
}
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/datastructures/stack/Stack.java
================================================
package com.bruis.algorithminjava.datastructures.stack;
/**
* @author LuoHaiYang
*/
public interface Stack {
int getSize();
boolean isEmpty();
void push(E e);
// 移除元素
E pop();
E peek();
}
================================================
FILE: src/main/java/com/bruis/algorithminjava/utils/SortTestHelper.java
================================================
package com.bruis.algorithminjava.utils;
import java.lang.reflect.Method;
/**
* @author LuoHaiYang
*/
public class SortTestHelper {
/**
* SortTestHelper不允许产生任何实例
*/
private SortTestHelper(){}
/**
* 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
* @param n
* @param rangeL
* @param rangeR
* @return
*/
public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) {
assert rangeL <= rangeR;
Integer[] arr = new Integer[n];
for (int i = 0; i < n; i++) {
arr[i] = new Integer((int) (Math.random() * (rangeR - rangeL + 1) + rangeL));
}
return arr;
}
/**
* 生成一个近乎有序的数组
* 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据
* swapTimes定义了数组的无序程度:
* swapTimes == 0 时, 数组完全有序
* swapTimes 越大, 数组越趋向于无序
* @param n
* @param swapTimes
* @return
*/
public static Integer[] generateNearlyOrderedArray(int n, int swapTimes){
Integer[] arr = new Integer[n];
for( int i = 0 ; i < n ; i ++ ) {
arr[i] = new Integer(i);
}
for( int i = 0 ; i < swapTimes ; i ++ ){
int a = (int)(Math.random() * n);
int b = (int)(Math.random() * n);
int t = arr[a];
arr[a] = arr[b];
arr[b] = t;
}
return arr;
}
/**
* 打印arr数组的所有内容
* @param arr
*/
public static void printArray(Object[] arr) {
for (int i = 0; i < arr.length; i++){
System.out.print( arr[i] );
System.out.print( ' ' );
}
System.out.println();
return;
}
/**
* 判断arr数组是否有序
* @param arr
* @return
*/
public static boolean isSorted(Comparable[] arr){
for( int i = 0 ; i < arr.length - 1 ; i ++ ) {
if (arr[i].compareTo(arr[i + 1]) > 0) {
return false;
}
}
return true;
}
/**
* 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间
* 将算法的运行时间打印在控制台上
* @param sortClassName
* @param arr
*/
public static void testSort(String sortClassName, Comparable[] arr){
// 通过Java的反射机制,通过排序的类名,运行排序函数
try{
// 通过sortClassName获得排序函数的Class对象
Class sortClass = Class.forName(sortClassName);
// 通过排序函数的Class对象获得排序方法
Method sortMethod = sortClass.getMethod("sort",new Class[]{Comparable[].class});
// 排序参数只有一个,是可比较数组arr
Object[] params = new Object[]{arr};
long startTime = System.currentTimeMillis();
// 调用排序函数
sortMethod.invoke(null,params);
long endTime = System.currentTimeMillis();
assert isSorted( arr );
System.out.println( sortClass.getSimpleName()+ " : " + (endTime-startTime) + "ms" );
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间
* 将算法的运行时间以long类型返回, 单位为毫秒(ms)
*
* @param sortClassName
* @param arr
* @return
*/
public static long testSort2(String sortClassName, Comparable[] arr){
// 通过Java的反射机制,通过排序的类名,运行排序函数
try{
// 通过sortClassName获得排序函数的Class对象
Class sortClass = Class.forName(sortClassName);
// 通过排序函数的Class对象获得排序方法
Method sortMethod = sortClass.getMethod("sort",new Class[]{Comparable[].class});
// 排序参数只有一个,是可比较数组arr
Object[] params = new Object[]{arr};
long startTime = System.currentTimeMillis();
// 调用排序函数
sortMethod.invoke(null,params);
long endTime = System.currentTimeMillis();
assert isSorted( arr );
return endTime - startTime;
}
catch(Exception e){
e.printStackTrace();
}
return 0;
}
}