Skip to content

Files

Latest commit

0603fe4 · Jan 16, 2025

History

History

1296.Divide Array in Sets of K Consecutive Numbers

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Jan 16, 2025
Jan 16, 2025
Jan 1, 2023
Jan 1, 2023
Oct 10, 2024
Jan 1, 2023
Oct 10, 2024
Jan 13, 2024
Oct 10, 2024
Jan 16, 2025
comments difficulty edit_url rating source tags
true
中等
1490
第 168 场周赛 Q2
贪心
数组
哈希表
排序

English Version

题目描述

给你一个整数数组 nums 和一个正整数 k,请你判断是否可以把这个数组划分成一些由 k 个连续数字组成的集合。
如果可以,请返回 true;否则,返回 false

 

示例 1:

输入:nums = [1,2,3,3,4,4,5,6], k = 4
输出:true
解释:数组可以分成 [1,2,3,4] 和 [3,4,5,6]。

示例 2:

输入:nums = [3,2,1,2,3,4,3,4,5,9,10,11], k = 3
输出:true
解释:数组可以分成 [1,2,3] , [2,3,4] , [3,4,5] 和 [9,10,11]。

示例 4:

输入:nums = [1,2,3,4], k = 3
输出:false
解释:数组不能分成几个大小为 3 的子数组。

 

提示:

  • 1 <= k <= nums.length <= 105
  • 1 <= nums[i] <= 109

 

注意:此题目与 846 重复:https://leetcode.cn/problems/hand-of-straights/

解法

方法一:哈希表 + 排序

我们用一个哈希表 cnt 统计数组 nums 中每个数字出现的次数,然后对数组 nums 进行排序。

接下来,我们遍历数组 nums ,对于数组中的每个数字 v ,如果 v 在哈希表 cnt 中出现的次数不为 0 ,则我们枚举 v v + k 1 的每个数字,如果这些数字在哈希表 cnt 中出现的次数都不为 0 ,则我们将这些数字的出现次数减 1 ,如果减 1 后这些数字的出现次数为 0 ,则我们在哈希表 cnt 中删除这些数字。否则说明无法将数组划分成若干个长度为 k 的子数组,返回 false。如果可以将数组划分成若干个长度为 k 的子数组,则遍历结束后返回 true

时间复杂度 O ( n × log n ) ,空间复杂度 O ( n ) 。其中 n 是数组 nums 的长度。

Python3

class Solution:
    def isPossibleDivide(self, nums: List[int], k: int) -> bool:
        cnt = Counter(nums)
        for v in sorted(nums):
            if cnt[v]:
                for x in range(v, v + k):
                    if cnt[x] == 0:
                        return False
                    cnt[x] -= 1
                    if cnt[x] == 0:
                        cnt.pop(x)
        return True

Java

class Solution {
    public boolean isPossibleDivide(int[] nums, int k) {
        Map<Integer, Integer> cnt = new HashMap<>();
        for (int v : nums) {
            cnt.merge(v, 1, Integer::sum);
        }
        Arrays.sort(nums);
        for (int v : nums) {
            if (cnt.containsKey(v)) {
                for (int x = v; x < v + k; ++x) {
                    if (!cnt.containsKey(x)) {
                        return false;
                    }
                    if (cnt.merge(x, -1, Integer::sum) == 0) {
                        cnt.remove(x);
                    }
                }
            }
        }
        return true;
    }
}

C++

class Solution {
public:
    bool isPossibleDivide(vector<int>& nums, int k) {
        unordered_map<int, int> cnt;
        for (int& v : nums) ++cnt[v];
        sort(nums.begin(), nums.end());
        for (int& v : nums) {
            if (cnt.count(v)) {
                for (int x = v; x < v + k; ++x) {
                    if (!cnt.count(x)) {
                        return false;
                    }
                    if (--cnt[x] == 0) {
                        cnt.erase(x);
                    }
                }
            }
        }
        return true;
    }
};

Go

func isPossibleDivide(nums []int, k int) bool {
	cnt := map[int]int{}
	for _, v := range nums {
		cnt[v]++
	}
	sort.Ints(nums)
	for _, v := range nums {
		if _, ok := cnt[v]; ok {
			for x := v; x < v+k; x++ {
				if _, ok := cnt[x]; !ok {
					return false
				}
				cnt[x]--
				if cnt[x] == 0 {
					delete(cnt, x)
				}
			}
		}
	}
	return true
}

方法二:有序集合

我们也可以使用有序集合统计数组 nums 中每个数字出现的次数。

接下来,循环取出有序集合中的最小值 v ,然后枚举 v v + k 1 的每个数字,如果这些数字在有序集合中出现的次数都不为 0 ,则我们将这些数字的出现次数减 1 ,如果出现次数减 1 后为 0 ,则将该数字从有序集合中删除,否则说明无法将数组划分成若干个长度为 k 的子数组,返回 false。如果可以将数组划分成若干个长度为 k 的子数组,则遍历结束后返回 true

时间复杂度 O ( n × log n ) ,空间复杂度 O ( n ) 。其中 n 是数组 nums 的长度。

Python3

class Solution:
    def isPossibleDivide(self, nums: List[int], k: int) -> bool:
        if len(nums) % k != 0:
            return False
        sd = SortedDict()
        for h in nums:
            if h in sd:
                sd[h] += 1
            else:
                sd[h] = 1
        while sd:
            v = sd.peekitem(0)[0]
            for i in range(v, v + k):
                if i not in sd:
                    return False
                if sd[i] == 1:
                    sd.pop(i)
                else:
                    sd[i] -= 1
        return True

Java

class Solution {
    public boolean isPossibleDivide(int[] nums, int k) {
        if (nums.length % k != 0) {
            return false;
        }
        TreeMap<Integer, Integer> tm = new TreeMap<>();
        for (int h : nums) {
            tm.merge(h, 1, Integer::sum);
        }
        while (!tm.isEmpty()) {
            int v = tm.firstKey();
            for (int i = v; i < v + k; ++i) {
                if (!tm.containsKey(i)) {
                    return false;
                }
                if (tm.merge(i, -1, Integer::sum) == 0) {
                    tm.remove(i);
                }
            }
        }
        return true;
    }
}

C++

class Solution {
public:
    bool isPossibleDivide(vector<int>& nums, int k) {
        if (nums.size() % k) {
            return false;
        }
        map<int, int> mp;
        for (int& h : nums) {
            mp[h] += 1;
        }
        while (!mp.empty()) {
            int v = mp.begin()->first;
            for (int i = v; i < v + k; ++i) {
                if (!mp.contains(i)) {
                    return false;
                }
                if (--mp[i] == 0) {
                    mp.erase(i);
                }
            }
        }
        return true;
    }
};

Go

func isPossibleDivide(nums []int, k int) bool {
	if len(nums)%k != 0 {
		return false
	}
	m := treemap.NewWithIntComparator()
	for _, h := range nums {
		if v, ok := m.Get(h); ok {
			m.Put(h, v.(int)+1)
		} else {
			m.Put(h, 1)
		}
	}
	for !m.Empty() {
		v, _ := m.Min()
		for i := v.(int); i < v.(int)+k; i++ {
			if _, ok := m.Get(i); !ok {
				return false
			}
			if v, _ := m.Get(i); v.(int) == 1 {
				m.Remove(i)
			} else {
				m.Put(i, v.(int)-1)
			}
		}
	}
	return true
}