力扣100热题[哈希]:最长连续序列

原题:128. 最长连续序列

题解:

官方题解:. - 力扣(LeetCode)题解,最长连续序列 :哈希表

官方解题思路是先去重,然后判断模板长度的数值是否存在,存在就刷新,最终找到最大值。

这里我自己研究了下,实际也是暴力解法。纯暴力解法会超时,这里利用了二分法查找的理念

  • 首先去重
  • 然后排序
  • 固定begin,然后找最大的end,返回max=end-begin+1使用二分法理念进行查找
  • 依次遍历,在end-begin<curmax已经找到的最大值,返回curmax +1

自己尝试了下,部分通过,有些边界值不太好控制,而且输入里面有负数,也不太好计算。

还有一种解题方法,就是在官方题解上做个变化,

  • 首先去重
  • 然后排序
  • 依次遍历,找到满足nums[i + 1] = nums[i] + 1的最长子数组,返回其长度。

代码:

func longestConsecutive(nums []int) int {
    // 如果数组为空,或者只有一个元素,直接返回数组长度
	if len(nums) <= 1 {
		return len(nums)
	}

	// 去重
	numSet := map[int]bool{}
	for _, num := range nums {
		numSet[num] = true
	}

	// 排序
	numTemp := make([]int, 0)
	for num := range numSet {
		numTemp = append(numTemp, num)
	}
	sort.Ints(numTemp)
	// fmt.Printf("numTemp %v\n", numTemp)

	// 暴力解法
	longestStreak := 0
	for begin := range numTemp {
		// 当剩余的个数,小于当前最大长度,则后面不可能有满足条件的更大的值,返回
		if begin+longestStreak > len(numTemp) {
			return longestStreak + 1
		}
		temp := BinarySearchMatch(numTemp, begin, longestStreak)
		if longestStreak < temp {
			longestStreak = temp
		}
	}
	return longestStreak + 1
}

func BinarySearchMatch(numTemp []int, begin, cur int) int {
	longestStreak := cur
	// 当前最大可用差值
	curMaxDiff := len(numTemp) - begin - 1
	// 使用二分法的理念,查询满足条件的数据
	for end := len(numTemp) - 1; end > begin; {
		// fmt.Printf("begin %v, end %v, curMaxDiff %v\n", begin, end, curMaxDiff)
		// 索引差值超过最大值,返回,end超过数组范围,返回
		if curMaxDiff >= len(numTemp) || end >= len(numTemp) {
			break
		}
		// 差值为0时,有可能会遗漏一个,判断end的下一个是否满足条件
		if curMaxDiff == 0 {
			if end < len(numTemp)-1 && numTemp[end+1]-numTemp[begin] == end+1-begin {
				longestStreak = end + 1 - begin
			}
            
			if end > begin && numTemp[end-1]-numTemp[begin] == end-1-begin {
				longestStreak = end - 1 - begin
			}

            if end > begin && numTemp[end]-numTemp[begin] == end-begin {
				longestStreak = end - begin
			}
			break
		}
		// 数值差值
		valDiff := numTemp[end] - numTemp[begin]
		// 索引差值
		indexDiff := end - begin

		// 二分法找到合适的索引end
		// 索引差值 < 数值差值,数值太大了,中间有不连续的,往前移动curMaxDiff/2
		if valDiff > indexDiff && indexDiff != 0 {
			curMaxDiff = curMaxDiff / 2
			end = end - curMaxDiff
			continue
		}

		// 索引差值 > 数值差值,这种不可能存在,因为已经去重了
		// 索引差值 = 数值差值,后面可能还有满足条件的,继续找
		if valDiff == indexDiff {
			// 刷新最大值
			if longestStreak > valDiff {
				break
			}

			longestStreak = valDiff
			// end后移curMaxDiff/2
			curMaxDiff = curMaxDiff / 2
			end = end + curMaxDiff
			continue
		}
	}

	return longestStreak
}

第二种方法

func longestConsecutive(nums []int) int {
    // 如果数组为空,或者只有一个元素,直接返回数组长度
	if len(nums) <= 1 {
		return len(nums)
	}

	// 去重
	numSet := map[int]bool{}
	for _, num := range nums {
		numSet[num] = true
	}

	// 排序
	numTemp := make([]int, 0)
	for num := range numSet {
		numTemp = append(numTemp, num)
	}
	sort.Ints(numTemp)
	//fmt.Printf("numTemp %v\n", numTemp)

	// 暴力解法
	longestStreak := 0
	for num := range numTemp {
		if num < len(numTemp)-1 && numTemp[num]+1 == numTemp[num+1] {
			currentNum := num
			currentStreak := 1
			for currentNum < len(numTemp)-1 && numTemp[currentNum]+1 == numTemp[currentNum+1] {
				currentNum++
				currentStreak++
			}
			if longestStreak < currentStreak {
				longestStreak = currentStreak
			}
		}
	}
	return longestStreak
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值