Solution/src/solution/Solution.java

406 lines
14 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package solution;
import java.util.*;
import java.util.stream.Collectors;
public class Solution {
//给定一个字符串 s ,找出其中不含有重复字符的 最长子串 的长度。
public static int lengthOfLongestSubstring(String s) {
// 哈希集合,记录每个字符是否出现过
Set<Character> occ = new HashSet<Character>();
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<Integer, Integer> 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<n+1;i++) {
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
/**
* 给定一个已排序的链表的头 head 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
* @param head
* @return
*/
public static ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
while (current!= null && current.next != null){
if (current.val == current.next.val){
current.next = current.next.next;
}else {
current = current.next;
}
}
return head;
}
}