剑指 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太水