剑指 Offer 53 - I. 在排序数组中查找数字 I / 剑指 Offer 42. 连续子数组的最大和(线段树基础)/152. 乘积最大子数组 / 面试题 10.02. 变位词组

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 53 - I. 在排序数组中查找数字 I / 剑指 Offer 42. 连续子数组的最大和(线段树基础)/152. 乘积最大子数组 / 面试题 10.02. 变位词组相关的知识,希望对你有一定的参考价值。

剑指 Offer 53 - I. 在排序数组中查找数字 I

2021.7.16 每日一题

题目描述

统计一个数字在排序数组中出现的次数。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: 0

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

二分查找,第一次二分找出现target最左边的位置,第二次找大于target的第一个位置,边界和判断上稍有不同
要代码复用的话,可以将第二个二分查找,查找的目标变为找target+1插入的下标,如果有target+1存在的话,就是最左边的下标。

class Solution {
    public int search(int[] nums, int target) {
        //两个二分,找左右边界把
        int n = nums.length;
        if(n == 0)
            return 0;
        int left = 0;
        int right = n - 1;
        while(left < right){
            int mid = (right - left) / 2 + left;
            if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid;
            }
        }
        if(nums[left] != target)
            return 0;
        int l = left;
        left = 0;
        right = n;
        while(left < right){
            int mid = (right - left) / 2 + left;
            if(nums[mid] <= target){
                left = mid + 1;
            }else{
                right = mid;
            }
        }            
        return left - l;
    }
}

代码复用

class Solution {
    public int search(int[] nums, int target) {
        //两个二分,找左右边界把
        int n = nums.length;
        if(n == 0)
            return 0;
        int l = binarySearch(0, n - 1, target, nums);
        if(nums[l] != target)
            return 0;
        return binarySearch(0, n, target + 1, nums) - l;
    }

    public int binarySearch(int left, int right, int target, int[] nums){
        while(left < right){
            int mid = (right - left) / 2 + left;
            if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid;
            }
        }
        return left;
    }
}

剑指 Offer 42. 连续子数组的最大和

2021.7.17 每日一题

题目描述

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

示例1:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

第n次做这个题了

class Solution {
    public int maxSubArray(int[] nums) {
        int l = nums.length;
        int res = nums[0];
        int max = nums[0];
        for(int i = 1; i < l; i++){
            max = Math.max(max + nums[i], nums[i]);
            res = Math.max(res, max);
        }
        return res;
    }
}

为了能学习到线段树,加深印象,官解给的第二种方法也写一遍

class Solution {
    //为了能对线段树有点印象,自己来写一下官解给的第二种方法

    //首先定义内部类,存储四个变量,分别表示以左端点开头的最大区间和lsum
    //以右断点结束的最大去见和,rsum
    //区间和isum,l到r之间的最大区间和msum
    class Status{
        int lsum, rsum, isum, msum;
        public Status(int l, int r, int i, int m){
            lsum = l;
            rsum = r;
            isum = i;
            msum = m;
        }
    }
    public int maxSubArray(int[] nums) {
        return getInfo(nums, 0, nums.length - 1).msum;
    }

    //分治
    public Status getInfo(int[] nums, int l, int r){
        if(l == r){
            return new Status(nums[l], nums[l], nums[l], nums[l]);
        }
        int mid = (l + r) / 2;
        Status left = getInfo(nums, l, mid);
        Status right = getInfo(nums, mid + 1, r);
        return cal(left, right);
    }
    //计算Status中的各个值
    public Status cal(Status left, Status right){
        int lsum = Math.max(left.lsum, left.isum + right.lsum);
        int rsum = Math.max(right.rsum, left.rsum + right.isum);
        int isum = left.isum + right.isum;
        int msum = Math.max(Math.max(left.msum, right.msum), left.rsum + right.lsum);
        return new Status(lsum, rsum, isum, msum);
    }
}

152. 乘积最大子数组

看三叶姐的扩展来看的题,可能当时也做过,但是没做明白

题目描述

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

示例 1:

输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-product-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

看了一眼,五个月前做的了,再一次感慨时间过得好快
思路就是动态规划,但是这里和子数组和不同的是,乘积有可能是负的,然后负负得正,从而得到最大

public class Solution {
    //动态规划,
    public int maxProduct(int[] nums) {
        int l = nums.length;
        //以当前为结尾的最大子数组乘积
        int[] f = new int[l];
        //以当前为结尾的最小子数组乘积
        int[] g = new int[l];

        f[0] = nums[0];
        g[0] = nums[0];
        int max = nums[0];
        for(int i = 1; i < l; i++){
            f[i] = Math.max(nums[i], Math.max(f[i - 1] * nums[i], g[i - 1] * nums[i]));
            g[i] = Math.min(nums[i], Math.min(f[i - 1] * nums[i], g[i - 1] * nums[i]));
            max = Math.max(f[i], max);
        }
        return max;
    }
}

面试题 10.02. 变位词组

2021.7.18 每日一题

题目描述

编写一种方法,对字符串数组进行排序,将所有变位词组合在一起。变位词是指字母相同,但排列不同的字符串。

注意:本题相对原题稍作修改

示例:

输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
输出:
[
[“ate”,“eat”,“tea”],
[“nat”,“tan”],
[“bat”]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/group-anagrams-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

咋说呢,想法很简单,就是map把一样表示的字符串放在一起就行了
我这里实现是统计了每个字符串的字母的个数,然后把这个数组转换成一个字符串形式的表示方法,当做map的键值
很快也就写好了,但是超过12,

刚开始想创建一个类来当做键值的,发现containsKey还是不太熟

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        //发现还是没太懂containsKey的底层逻辑,完了再看一下,我记得应该重写哈希和等于方法就行
        //所以这里直接用字符串当key把
        int l = strs.length;
        Map<String, List<String>> map = new HashMap<>();

        for(int i = 0; i < l; i++){
            String s = strs[i];
            int[] count = new int[26];
            for(int j = 0; j < s.length(); j++){
                char c = s.charAt(j);
                count[c - 'a']++;
            }   
            StringBuilder sb = new StringBuilder(); 
            for(int j = 0; j < 26; j++){
                if(count[j] == 0)
                    continue;
                int num = count[j];
                char c = (char)('a' + j);
                sb.append(c + String.valueOf(num));
            }
            String key = sb.toString();
            
            List<String> list = map.getOrDefault(key, new ArrayList<>());
            list.add(s);
            map.put(key, list);
        }
        List<List<String>> res = new ArrayList<>();
        for(Map.Entry<String, List<String>> entry : map.entrySet()){
            List<String> list = entry.getValue();
            res.add(list);
        }
        return res;
    }
}


//可以定义一个节点,表示map的键值
/*
class Node{
    int[] count;
    
    public Node(int[] c){
        count = c;
    }

    public int equals(Object o){
        if(this == o)
            return true;
        if(o == null || getClass() != o.getClass())
            return false;
        Node node = (Node)o;
        //比较逻辑,这里没有详细写
        if(count == node.count)
            return true;
        return false;
    }

    public int hashCode(){
	    //注意这里是Objects
        return Objects.hash(count);
    }
}
*/

看了下官解,发现我的写法和第二种方法基本一致
第一种方法,虽然说复杂度高,用了排序,但是代码少啊,竞赛需要这样的操作,学习一下
两个点,第一,直接将数组传入String的构造器,构造字符串
第二个,最后输出,直接用map.values()方法,输出的是一个value值组成的集合,然后将该集合传入list的构造器,生成列表。

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        for (String str : strs) {
            char[] array = str.toCharArray();
            Arrays.sort(array);
            String key = new String(array);
            List<String> list = map.getOrDefault(key, new ArrayList<String>());
            list.add(str);
            map.put(key, list);
        }
        return new ArrayList<List<String>>(map.values());
    }
}


作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/group-anagrams-lcci/solution/bian-wei-ci-zu-by-leetcode-solution-g2a8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

提交了一下,排序好快…

以上是关于剑指 Offer 53 - I. 在排序数组中查找数字 I / 剑指 Offer 42. 连续子数组的最大和(线段树基础)/152. 乘积最大子数组 / 面试题 10.02. 变位词组的主要内容,如果未能解决你的问题,请参考以下文章

算法剑指 Offer 53 - I. 在排序数组中查找数字 I

[LeetCode]剑指 Offer 53 - I. 在排序数组中查找数字 I

剑指 Offer 53 - I. 在排序数组中查找数字 I太水

剑指 Offer 53 - I. 在排序数组中查找数字 I太水

剑指Offer面试题53 - I. 在排序数组中查找数字 I

每日一题 - 剑指 Offer 53 - I. 在排序数组中查找数字 I