Leetcode每日一题-2021.04-part2

Leetcode-2021.04-part2

4.17-220.存在重复元素Ⅲ

题目描述
在这里插入图片描述

方法一:暴力破解,索引区间搜索

分析

分析题意:

  1. 数组nums 和 参数k,t,要求:
    1. 在数组中存在两个数 nums[i], nums[j]
    2. 满足 nums[i], nums[j]差的绝对值 <= t
    3. 且 i 与 j 的差值的绝对值 <=k
  2. 不妨设 i < j
  3. 遍历数组nums
    1. 以i为起点, k为区间长度,搜索 [i, i+k] 区间是否有符合值
    2. 如果有,返回true

代码

func containsNearbyAlmostDuplicate(nums []int, k int, t int) bool {
	// abs的设计 go语言的int 是 int32往上升级的,所以不会越界
	// 如果是java语言,v建议用long接收,返回long 这样不会有越界问题
	abs := func(v int) int {
		if v < 0 {
			return -v
		}
		return v
	}
	// k 区间跨度, t 值跨度
	// 遍历每一个元素
	for i := 0; i < len(nums); i++ {
		// 以当前元素为起点,k为跨度搜索
		for j := i+1; j < len(nums) && j <= i+k; j++ {
			if abs(nums[j] - nums[i]) <= t {
				return true
			}
		}
	}
	return false
}

方法二:值域分桶+滑动窗口

分析

维护一个桶,桶的设计是这样的:

  1. a - b <= t 得到a,b的最大区间长度t+1
  2. 假设值为v, 那么以v/(t+1)作为区间映射
    1. 比如t为8 v为1, v就落在0号区间
    2. v为-1, 那么v应该落在-1区间 桶作映射判断

窗口滑动,每k个元素为一个窗口

  1. 由于此时维护了桶,当窗口达到k长度时,下一个元素开始作滑动维护(详情见代码)

判断依据:

  1. 如果当前值已经有桶存在,一定为true
  2. 如果当前值桶不存在,判断相邻桶是否存在,存在则比较桶内值是否满足要求

代码

func containsNearbyAlmostDuplicate(nums []int, k int, t int) bool {
	// abs的设计 go语言的int 是 int32往上升级的,所以不会越界
	// 如果是java语言,v建议用long接收,返回long 这样不会有越界问题
	// 绝对值计算
	abs := func(num int) int {
		if num < 0 {
			return -num
		}
		return num
	}
	// 桶计算
	getBucket := func(num int) int {
		if num >= 0 {
			return num/(t+1)
		}
		// 负数解释 因为-1 -> -t+1 如果直接除 会落在0号位上和-1号位上,所以作处理
		// 0 -> -(t) 落在0号位上 -1 落在-1号位上
		return (num+1)/(t+1)-1
	}
	// 维护桶和桶内最近值
	buckets := make(map[int]int)
	for i, v := range nums {
		bucket := getBucket(v)
		// 如果存在桶,true
		if _, exist := buckets[bucket]; exist {
			return true
		}
		// 不存在桶,那么判断相邻桶
		// 如果左边桶存在,判断桶值val和当前值v 是否满足条件
		if val, exist := buckets[bucket-1]; exist && abs(v-val) <= t {
			return true
		}
		// 如果右边桶存在,判断桶值val和当前值 是否满足条件
		if val, exist := buckets[bucket+1]; exist && abs(v-val) <= t {
			return true
		}
		// 将当前桶维护到buckets里
		buckets[bucket] = v
		// 最关键的点:滑动窗口 k是区间长度 i 从0,k-1的长度已经达到k
		// 所以窗口滑动开始维护的点是在等于k的时候
		if i >= k {
			// 将k个之前的桶删掉,保证当前的桶量符合窗口区间
			delete(buckets, getBucket(nums[i-k]))
		}
	}
	// 遍历结束都不满足,返回false
	return false
}

4.18-26.删除有序数组中的重复项

题目描述
在这里插入图片描述
在这里插入图片描述
分析

简单题:双指针即可

代码

// bug题,即使不做严谨性判断,代码也能通过 而此时返回的至少是1
func removeDuplicates(nums []int) int {
	// 严谨性判断
	if len(nums) == 0 {
		return 0
	}
	// 维护一个假想栈
	top := 0
	for i := 1; i < len(nums); i++ {
		// 栈顶元素等于当前元素则继续
		if nums[top] == nums[i] {
			continue
		}
		// 否则当前元素加入栈顶
		top++
		nums[top] = nums[i]
	}
	// 返回栈长
	return top+1
}

4.19-27.移除元素

题目描述

在这里插入图片描述
分析

简单题,双指针即可

代码

func removeElement(nums []int, val int) int {
	top := 0
	for i := 0; i < len(nums); i++ {
		if nums[i] != val {
			nums[top] = nums[i]
			top++
		}
	}
	return top
}

4.20-28.实现strStr()

题目描述
在这里插入图片描述
在这里插入图片描述
分析

根据题意,

  1. 如果needle=="",直接return 0
  2. 遍历haystack,找到第一个与needle[0]相等的字符量,记录当前的索引,就遍历往下继续比;
    1. 如果needle被遍历结束,说明找到相同的了,返回之前记录的索引;
    2. 如果中途出现一个不和needle的字符一致的,那么重置needle,找下一个位置和needle[0]相同,重复2.1 ,2.2
  3. 临界条件:
    1. 当haystack遍历完了还没结果,那么返回-1;
    2. 遍历匹配needle元素的时候,别忘记判断haystack是否越界

时间复杂度:O(nm) n为haystack长度,m为needle长度

代码

func strStr(haystack string, needle string) int {
	// 根据题意,如果为空串,那么返回0
	if len(needle) == 0 {
		return 0
	}
flag: // 外循环标志
	for i := range haystack {
		// 如果当前值和needle[0]匹配不上,继续遍历下一个值
		if haystack[i] != needle[0] {
			continue
		}
		// 匹配上之后,先记录当前索引,以便可以返回
		index := i
		// 从当前位置开始,和needle一一比较
		for j := 0; j < len(needle); j++ {
			// 存在某一个字符不匹配,退出比较循环,继续外层循环
			if haystack[i] != needle[j] {
				continue flag
			}
			i++
			// 循环比较的时候,haystack指针i同时变动,所以需要判断指针越界情况,如果i已经越界了,而j还未遍历完,那么 说明匹配不上
            if i == len(haystack) && j+1 != len(needle) {
				return -1
			}
		}
		// 如果比较循环能够走完,说明index可以返回
		return index
	}
	return -1
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值