package solution; import java.util.*; import java.util.stream.Collectors; public class Solution { //给定一个字符串 s ,找出其中不含有重复字符的 最长子串 的长度。 public static int lengthOfLongestSubstring(String s) { // 哈希集合,记录每个字符是否出现过 Set occ = new HashSet(); int n = s.length(); // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动 int rk = -1, ans = 0; for (int i = 0; i < n; ++i) { if (i != 0) { // 左指针向右移动一格,移除一个字符 occ.remove(s.charAt(i - 1)); } while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) { // 不断地移动右指针 occ.add(s.charAt(rk + 1)); ++rk; } // 第 i 到 rk 个字符是一个极长的无重复字符子串 ans = Math.max(ans, rk - i + 1); } return ans; } //计算最大价格 public static int maxProfit(int[] prices) { if (prices == null || prices.length == 0) { return 0; } int minPrice = prices[0]; int maxProfit = 0; for (int price : prices) { // 更新最小价格 minPrice = Math.min(minPrice, price); // 计算当前价格的潜在利润并更新最大利润 int potentialProfit = price - minPrice; maxProfit = Math.max(maxProfit, potentialProfit); } return maxProfit; } //哈希映射算法(Hash Mapping Algorithm)用于找出一个数组中的众数(majority element) public static int majorityElement(int[] nums) { Map map = new HashMap<>(); // maxNum 表示元素,maxCount 表示元素出现的次数 int maxNum = 0, maxCount = 0; for (int num: nums) { int count = map.getOrDefault(num, 0) + 1; map.put(num, count); if (count > maxCount) { maxCount = count; maxNum = num; } } return maxNum; } //摩尔投票算法(Boyer-Moore Voting Algorithm)来找出数组中的众数 public static int majorityElement1(int[] nums) { int candidate = nums[0], count = 1; for (int i = 1; i < nums.length; ++i) { if (count == 0) { candidate = nums[i]; count = 1; } else if (nums[i] == candidate) { count++; } else{ count--; } } return candidate; } //合并数组冒泡排序实现 public static void merge(int[] nums1, int m, int[] nums2, int n) { System.arraycopy(nums2, 0, nums1, m, n); // 冒泡排序 for (int i = 0; i < nums1.length; i++) { for (int j = 0; j < nums1.length; j++) { if (i != j) { if (nums1[i] < nums1[j]){ int temp = nums1[i]; nums1[i] = nums1[j]; nums1[j] = temp; } } } } String result = Arrays.stream(nums1).mapToObj(String::valueOf).collect(Collectors.joining(",", "[", "]")); System.out.println(result); } // public static String longestCommonPrefix(String[] strs) { // int index = 0; // StringBuilder temp = new StringBuilder(); // if (strs != null){ // for (int k = 0; k < strs[0].length(); k++) { // char indexChar = strs[0].charAt(index); // if (strs.length == 1){ // return strs[0]; // } // for (int i = 1; i < strs.length; i++) { // if (strs[i] != ""){ // for (int j = 0; j < 1; j++) { // if (index >= strs[i].length()){ // return String.valueOf(temp); // } // char crrChar = strs[i].charAt(index); // if (indexChar != crrChar){ // return String.valueOf(temp); // } // if (i == strs.length- 1){ // temp.append(crrChar); // index++; // } // } // } else { // return ""; // } // } // } // return String.valueOf(temp); // } // return ""; // } /** * 编写一个函数来查找字符串数组中的最长公共前缀。 * 如果不存在公共前缀,返回空字符串 ""。 * @param strs 数组 * @return 最长公共前缀 */ public static String longestCommonPrefix(String[] strs) { if (strs == null || strs.length == 0) { return ""; } int length = strs[0].length(); int count = strs.length; for (int i = 0; i < length; i++) { char c = strs[0].charAt(i); for (int j = 1; j < count; j++) { if (i == strs[j].length() || strs[j].charAt(i) != c) { return strs[0].substring(0, i); } } } return strs[0]; } /** 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 */ public static int removeElement(int[] nums, int val) { int i = 0; for (int j = 0; j < nums.length; j++) { if (nums[j] != val) { nums[i] = nums[j]; i++; } } return i; } /** * 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。 * 元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 */ public static int removeDuplicates(int[] nums) { if (nums.length == 0) return 0; int i = 1; // 从第二个元素开始检查 for (int j = 1; j < nums.length; j++) { if (nums[j] != nums[j - 1]) { nums[i] = nums[j]; i++; } } return i; } /** * 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 * 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 * @param nums * @return */ public static boolean canJump(int[] nums) { int maxReach = 0; // 初始化最远可到达的位置为0 for (int i = 0; i < nums.length; i++) { if (i > maxReach) { // 如果当前索引超过了最远可到达的位置,说明无法到达终点 return false; } // 更新最远可到达的位置 maxReach = Math.max(maxReach, i + nums[i]); } return true; } /** * 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 * @param list1 * @param list2 * @return */ public ListNode mergeTwoLists(ListNode list1, ListNode list2) { ListNode dummy = new ListNode(0); ListNode current = dummy; while (list1 != null && list2 != null) { if (list1.val < list2.val) { current.next = list1; list1 = list1.next; } else { current.next = list2; list2 = list2.next; } current = current.next; } if (list1 != null){ current.next = list1; } else if (list2 != null){ current.next = list2; } return dummy.next; } /** *给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 * @param haystack * @param needle * @return */ public int strStr(String haystack, String needle) { if (needle.isEmpty()) return -1; return haystack.indexOf(needle); } /** * 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 * * 请必须使用时间复杂度为 O(log n) 的算法。 * @param nums * @param target * @return */ public int searchInsert(int[] nums, int target) { if (nums.length == 0) return 0; for (int i = 0; i < nums.length; i++) { if (nums[i] >= target) { return i; } } return nums.length; } /** * 给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 * * 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 * @param s * @return */ public int lengthOfLastWord(String s) { if (s.isEmpty()) return 0; for (int i = s.length() - 1; i >= 0; i--) { if (s.charAt(i) != ' ') { int count = 0; while (i >= 0 && s.charAt(i) != ' ') { count++; i--; } return count; } } return 0; } /** * 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 * * 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 * * 你可以假设除了整数 0 之外,这个整数不会以零开头。 * @param digits * @return */ public static int[] plusOne(int[] digits) { int n = digits.length; // 从数组的最后一位开始处理进位 for (int i = n - 1; i >= 0; i--) { if (digits[i] < 9) { digits[i]++; return digits; } // 如果当前位是9,则将其置为0 digits[i] = 0; } // 如果所有的数字都是9,那么会到这里 // 创建一个新的数组,其长度比原数组多1 int[] newNumber = new int[n + 1]; newNumber[0] = 1; return newNumber; } /** * 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 * * 输入为 非空 字符串且只包含数字 1 和 0。 * @param a * @param b * @return */ public static String addBinary(String a, String b) { StringBuilder result = new StringBuilder(); // 用于存储结果 int carry = 0; // 进位 int i = a.length() - 1, j = b.length() - 1; // 指向字符串a和b的最后一位 // 当i或j在范围内,或有进位时,继续循环 while (i >= 0 || j >= 0 || carry == 1) { int sum = carry; // 当前位的和,初始为进位 // 如果i在范围内,加上a的当前位 if (i >= 0) { sum += a.charAt(i) - '0'; // 将字符转换为数字 i--; // 移动到下一位 } // 如果j在范围内,加上b的当前位 if (j >= 0) { sum += b.charAt(j) - '0'; // 将字符转换为数字 j--; // 移动到下一位 } result.append(sum % 2); // 当前位的结果 carry = sum / 2; // 更新进位 } return result.reverse().toString(); // 反转结果并返回 } /** *给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 * 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 * 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。 * * @param x * @return */ public static int mySqrt(int x) { if (x < 2){ return x; } long guess = x / 2; while (guess * guess > x){ guess = (guess + x/guess)/2; } return (int) guess; } /** * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? * @param n * @return */ public static int climbStairs(int n) { if(n < 3)return n; int dp[]=new int[n+1]; dp[1]=1; dp[2]=2; for(int i=3;i