diff --git "a/notes/algorithms/\351\200\211\346\213\251\346\216\222\345\272\217\347\256\227\346\263\225.md" "b/notes/algorithms/\351\200\211\346\213\251\346\216\222\345\272\217\347\256\227\346\263\225.md" index 7b247d7..82b1ae2 100644 --- "a/notes/algorithms/\351\200\211\346\213\251\346\216\222\345\272\217\347\256\227\346\263\225.md" +++ "b/notes/algorithms/\351\200\211\346\213\251\346\216\222\345\272\217\347\256\227\346\263\225.md" @@ -30,7 +30,7 @@ public class SelectionSort { for (int i = 0; i < n; i++) { int min = i; - for (int j = i+1; i < n; i++) { + for (int j = i+1; j < n; i++) { if (arr[j] < arr[min]) { min = j; } diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/ContainsDuplicate_217.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/ContainsDuplicate_217.java new file mode 100644 index 0000000..924d68c --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/ContainsDuplicate_217.java @@ -0,0 +1,111 @@ +package com.bruis.algorithminjava.algorithm.leetcode; + +import java.util.*; + +/** + * 217: Contains Duplicate + * @Description + * @Author luohaiyang + * @Date 2022/6/24 + */ +public class ContainsDuplicate_217 { + + public static void main(String[] args) { + int[] test = {1, 2, 30, 22, 3, 4, 5, 1}; + System.out.println(containsDuplicate(test)); + } + + public static boolean containsDuplicate(int[] nums) { + // 数组类型题思考步骤: + // 1) 入参是否合法,是否越界等; + // 2) 是否是有序; + // 3) 是否有负数; + + // 题解思路: + // 1. 暴力破解法; O(n^2); + // 2. 桶排序? + // 2.1 需要Map数据结构; + // 2.2 不需要Map数据结构; + // 3. 排序之后,判断前后数字是否一样; + + return false; + } + + public static boolean setSolution(int[] nums) { + int n = nums.length; + if (n < 1) { + return false; + } + Set set = new HashSet(); + for (int x : nums) { + if (!set.add(x)) { + return true; + } + } + return false; + } + + /** + * 通过排序来进行筛选 + * @param nums + * @return + */ + public static boolean sortSolution(int[] nums) { + int n = nums.length; + if (n < 1) { + return false; + } + Arrays.sort(nums); + for (int i = 1; i < nums.length - 1; i++) { + if (nums[i] == nums[i+1]) { + return true; + } + } + return false; + } + + /** + * 基于桶排序 + * @param nums + * @return + */ + public static boolean bucketMapSolution(int[] nums) { + int n = nums.length; + if (n < 1) { + return false; + } + + Map duplicateMap = new HashMap<>(n); + + for (int i = 0; i < n; i++) { + if (!duplicateMap.containsKey(nums[i])) { + duplicateMap.put(nums[i], 1); + continue; + } + return true; + } + return false; + } + + /** + * 暴力解法 + * @param nums + * @return + */ + public static boolean violentSolution(int[] nums) { + if (nums.length < 1) { + return false; + } + + // 方法一:暴力解法 + int n = nums.length; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (i != j && nums[i] == nums[j]) { + return true; + } + } + } + return false; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/LongestPalindromicSubstring_5.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/LongestPalindromicSubstring_5.java new file mode 100644 index 0000000..2c84640 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/LongestPalindromicSubstring_5.java @@ -0,0 +1,9 @@ +package com.bruis.algorithminjava.algorithm.leetcode; + +/** + * @Description + * @Author luohaiyang + * @Date 2022/6/28 + */ +public class LongestPalindromicSubstring_5 { +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/MaximumSubarray_53.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/MaximumSubarray_53.java new file mode 100644 index 0000000..f59db25 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/MaximumSubarray_53.java @@ -0,0 +1,68 @@ +package com.bruis.algorithminjava.algorithm.leetcode; + +/** + * @Description + * @Author luohaiyang + * @Date 2022/6/24 + */ +public class MaximumSubarray_53 { + + public static void main(String[] args) { + // 条件: + // 1. 连续数组(不可以排序); + + // 解题思路: + // 1. 暴力解法;(超时) + // 2. 正确解法-动态规划; + + // 有卡顿、纠结的点: + // 1. 算法起始条件、结束条件; + + int[] nusm = {-2,1,-3,4,-1,2,1,-5,4}; + System.out.println(violentSolution(nusm)); + } + + public static int violentSolution(int[] nums) { + int n = nums.length; + if (n < 2) { + return nums[0]; + } + int max = nums[0];; + for (int i = 0; i < n; i++) { + int subTotal = nums[i]; + for (int j = i + 1; j < n; j++) { + if (max < nums[j]) { + max = nums[j]; + } + subTotal += nums[j]; + if (max < subTotal) { + max = subTotal; + } + } + } + return max; + } + + public static int maxSubArray(int[] nums) { + int n = nums.length; + if (n < 2) { + return nums[0]; + } + int max = nums[0]; + int i = 0, j = i + 1; + while (j < n) { + if (max < nums[j]) { + max = nums[j]; + } + int totalMax = 0; + for (int k = i; k < j; k++) { + totalMax += nums[i] + nums[j]; + } + if (max < totalMax) { + max = totalMax; + } + j++; + } + return max; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSum.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSum.java new file mode 100644 index 0000000..c3dea2f --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSum.java @@ -0,0 +1,90 @@ +package com.bruis.algorithminjava.algorithm.leetcode; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Description + * @Author luohaiyang + * @Date 2022/4/28 + */ +public class TwoSum { + public int[] twoSum(int[] nums, int target) { + // 暴力破解法 +// return forceSolution(nums, target); + return optimizeSolution01(nums, target); + } + + /** + * 对optimizeSolution01进行优化,少进行一次for循环 + * 时间复杂度: O(n) + * 空间复杂度:O(n) + * @param nums + * @param target + * @return + */ + private int[] optimizeSolution02(int[] nums, int target) { + int n = nums.length; + Map arrayMap = new HashMap<>(); + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (arrayMap.containsKey(target - num)) { + return new int[]{arrayMap.get(target - num), i}; + } + arrayMap.put(num, i); + } + return new int[0]; + } + + /** + * 借助jdk hashmap, + * 时间复杂度: O(n) + * 空间复杂度:O(n) + * @param nums + * @param target + * @return + */ + private int[] optimizeSolution01(int[] nums, int target) { + int n = nums.length; + Map 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]; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSumII.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSumII.java new file mode 100644 index 0000000..79147f1 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/TwoSumII.java @@ -0,0 +1,62 @@ +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]; + } +} diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java index 389d4df..d75488f 100644 --- a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/IsPalindrome.java @@ -12,34 +12,7 @@ * @author LuoHaiYang */ public class IsPalindrome { - public boolean isPalindrome(String s) { - if (s.equals("") || s == null) { - return false; - } - String lowerCase = s.toLowerCase(); - char[] chars = lowerCase.toCharArray(); - - int left = 0, right = chars.length - 1; - - // a 97 z 97+26=125 - - while (left <= right) { - while (chars[left] < 97 || chars[left] > 125) { - left++; - } - while (chars[right] < 97 || chars[right] > 125) { - right--; - } - if (chars[left] != chars[right]) { - return false; - } - left++; - right--; - } - return true; - } - - public boolean isPalindrome2(String str) { + public boolean isPalindrome(String str) { int head = 0, tail = str.length() - 1; char a, b; while(head < tail) { diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java index 07014d3..522d1f0 100644 --- a/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java +++ b/src/main/java/com/bruis/algorithminjava/algorithm/leetcode/array/MaximumGap.java @@ -1,5 +1,7 @@ package com.bruis.algorithminjava.algorithm.leetcode.array; +import java.util.Arrays; + /** * 最大间距 * @@ -8,6 +10,102 @@ * @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; @@ -54,7 +152,7 @@ private void quickSort3ways(int[] nums, int left, int right) { } private int max(int i, int j) { - return i > j ? i : j; + return Math.max(i, j); } private void swap(int[] nums, int i, int j) { @@ -66,6 +164,7 @@ private void swap(int[] nums, int i, int j) { 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.maximumGap(test)); + System.out.println(maximumGap.maximumGapOptimize2(test)); } } diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java index 64db417..08c7be4 100644 --- a/src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/BucketSort.java @@ -1,5 +1,6 @@ package com.bruis.algorithminjava.algorithm.sort; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -50,6 +51,7 @@ public int[] doSort(int[] arr) { public static void main(String[] args) { BucketSort bucketSort = new BucketSort(10); - bucketSort.doSort(new int[]{4,1,3,2,6,9,9}); + int[] sort = bucketSort.doSort(new int[]{4, 1, 3, 2, 20, 6, 9, 9, 21, 19}); + System.out.println(Arrays.toString(sort)); } } diff --git a/src/main/java/com/bruis/algorithminjava/algorithm/sort/Heap.java b/src/main/java/com/bruis/algorithminjava/algorithm/sort/Heap.java new file mode 100644 index 0000000..f593c19 --- /dev/null +++ b/src/main/java/com/bruis/algorithminjava/algorithm/sort/Heap.java @@ -0,0 +1,122 @@ +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; + } +}