[学习笔记]leetcode每日五题9.24

每日五题(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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值