每日五题(9.24)
1.左右两边子数组的和相等
链接:https://leetcode.cn/problems/tvdfij/
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
输入:nums = [1,7,3,6,5,6]
输出:3
解释:
中心下标是 3 。
左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。
输入:nums = [1, 2, 3]
输出:-1
解释:
数组中不存在满足此条件的中心下标。
我的思路:使用两个数保存某个元素左边和右边所有元素和,left(初始化为0)和right(初始化是数组总和sum)。遍历nums中的每个元素,遍历某一个元素nums[i]时,我们使得left+=num[i-1],right-=nums[i],再比较left和right是否相等,如果相同,则返回坐标
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/tvdfij/solution/zuo-you-liang-bian-zi-shu-zu-de-he-xiang-5j4r/
来源:力扣(LeetCode)
//官方答案
class Solution {
public int pivotIndex(int[] nums) {
//total为数组总和
int total = Arrays.stream(nums).sum();
int sum = 0;
//sum为左侧和,
for (int i = 0; i < nums.length; ++i) {
//只要2sum+nums[i]=total,则左右两边和相等
//sum=total−nums[i] −sum,左右元素相等公式
if (2 * sum + nums[i] == total) {
return i;
}
sum += nums[i];
}
return -1;
}
}
2.不含重复字符的最大子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长连续子字符串 的长度。
示例:
链接:https://leetcode.cn/problems/wtcaE1/solution/
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子字符串是 "abc",所以其长度为 3。
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子字符串是 "b",所以其长度为 1。
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
输入: s = ""
输出: 0
思路解析:
我们使用滑动窗口的方法来处理此题,遍历每一个元素,以每一个元素为头,延伸至后面的元素,直至碰到了重复元素(重复元素使用哈希表进行判断,遍历的时候将元素加入至哈希表中),碰到了重复元素后,进行长度比较是否为最大的,是则更新,然后去掉头元素。此时rk右指针不变,再进行判断,如果其中还有重复,则继续右移左指针并去掉头元素,直至内部不存在重复为止
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/wtcaE1/solution/bu-han-zhong-fu-zi-fu-de-zui-chang-zi-zi-4g7m/
来源:力扣(LeetCode)
class Solution {
public 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;
}
}
3.最多删除一个字符得到回文
链接:https://leetcode.cn/problems/RQku0D/
输入: s = "aba"
输出: true
输入: s = "abca"
输出: true
解释: 可以删除 "c" 字符 或者 "b" 字符
思路解析:
使用双指针正常进行回文判断,如果碰到两个指针对应的字符不一样时,分两种情况,一种是删除左指针,余下的字符串继续进行回文判断;另一种则是删除右指针
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/RQku0D/solution/zui-duo-shan-chu-yi-ge-zi-fu-de-dao-hui-30b55/
来源:力扣(LeetCode)
class Solution {
public boolean validPalindrome(String s) {
//low为左指针,high为右指针
int low = 0, high = s.length() - 1;
while (low < high) {
char c1 = s.charAt(low), c2 = s.charAt(high);
//如果相同,则移动两个指针
if (c1 == c2) {
++low;
--high;
//如果不同,则对两个剩余的新字符串进行判断
} else {
return validPalindrome(s, low, high - 1) || validPalindrome(s, low + 1, high);
}
}
return true;
}
public boolean validPalindrome(String s, int low, int high) {
for (int i = low, j = high; i < j; ++i, --j) {
char c1 = s.charAt(i), c2 = s.charAt(j);
if (c1 != c2) {
return false;
}
}
return true;
}
}
4.回文子字符串的个数
链接:https://leetcode.cn/problems/a7VOhD/
给定一个字符串 s
,请计算这个字符串中有多少个回文子字符串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
输入:s = "abc"
输出:3
解释:三个回文子串: "a", "b", "c"
输入:s = "aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
思路解析:
中心拓展,我们枚举遍历每一个可能的回文中心,并从回文中心开始,向左右两边进行拓展,每拓展一次,就计数+1,当然回文中心也需要被计数。注意回文中心有两种情况,一种是单字符的,一种是双字符的
class Solution {
public int countSubstrings(String s) {
int n = s.length(), ans = 0;
//i遍历到2n-1.可以同时遍历所有单字符和双字符的回文中心
for (int i = 0; i < 2 * n - 1; ++i) {
//当i为奇数时,回文中心为双字符,当i为偶数时,回文中心为单字符
//l为左指针,r为右指针
int l = i / 2, r = i / 2 + i % 2;
//判断是否到达边界和是否回文
while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {
--l;
++r;
++ans;
}
}
return ans;
}
}
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/a7VOhD/solution/hui-wen-zi-zi-fu-chuan-de-ge-shu-by-leet-ejfv/
来源:力扣(LeetCode)
5.最接近的三数之和
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
链接:https://leetcode.cn/problems/3sum-closest
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
输入:nums = [0,0,0], target = 1
输出:0
思路解析:
和三数之和这题的思路类似,我们同样使用双指针加排序的方式,枚举每一个元素,然后使用双指针进行判断。答案的更新在于与目标值的差值绝对值更小,当绝对值更小时,我们更新答案。当总和大于目标值时,我们右指针左移,小于目标时,左指针右移,当左右指针重合,结束该层循环。
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int n = nums.length;
int best = 10000000;
// 枚举 a
for (int i = 0; i < n; ++i) {
// 保证和上一次枚举的元素不相等
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 使用双指针枚举 b 和 c
int j = i + 1, k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
// 如果和为 target 直接返回答案
if (sum == target) {
return target;
}
// 根据差值的绝对值来更新答案
if (Math.abs(sum - target) < Math.abs(best - target)) {
best = sum;
}
if (sum > target) {
// 如果和大于 target,移动 c 对应的指针
int k0 = k - 1;
// 移动到下一个不相等的元素
while (j < k0 && nums[k0] == nums[k]) {
--k0;
}
k = k0;
} else {
// 如果和小于 target,移动 b 对应的指针
int j0 = j + 1;
// 移动到下一个不相等的元素
while (j0 < k && nums[j0] == nums[j]) {
++j0;
}
j = j0;
}
}
}
return best;
}
}
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/3sum-closest/solution/zui-jie-jin-de-san-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)