Skip to content

feat: add solutions to lc problem: No.2910 #1871

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,34 +64,197 @@

<!-- 这里可写通用的实现逻辑 -->

**方法一:哈希表 + 枚举**

我们用一个哈希表 $cnt$ 统计数组 $nums$ 中每个数字出现的次数,我们记数字次数的最小值为 $k$,那么我们可以在 $[k,..1]$ 的范围内枚举分组的大小。由于每个组的大小差值不超过 $1$,那么分组大小为 $k$ 或 $k+1$。

对于当前枚举到的分组大小 $k$,我们遍历哈希表中的每个次数 $v$,如果 $\lfloor \frac{v}{k} \rfloor < v \bmod k$,那么说明无法将这个次数 $v$ 分成 $k$ 个或 $k+1$ 个数值相同的组,因此我们可以直接跳过这个分组大小 $k$。否则,说明可以分组,我们只需要尽可能分出最多的分组大小 $k+1$,即可保证得到最小的分组数,因此我们可以将 $v$ 个数分成 $\lceil \frac{v}{k+1} \rceil$ 组,累加到当前枚举的答案中。由于我们是按照 $k$ 从大到小枚举的,因此只要找到了一个合法的分组方案,那么一定是最优的。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $nums$ 的长度。

<!-- tabs:start -->

### **Python3**

<!-- 这里可写当前语言的特殊实现逻辑 -->

```python

class Solution:
def minGroupsForValidAssignment(self, nums: List[int]) -> int:
cnt = Counter(nums)
for k in range(min(cnt.values()), 0, -1):
ans = 0
for v in cnt.values():
if v // k < v % k:
ans = 0
break
ans += (v + k) // (k + 1)
if ans:
return ans
```

### **Java**

<!-- 这里可写当前语言的特殊实现逻辑 -->

```java

class Solution {
public int minGroupsForValidAssignment(int[] nums) {
Map<Integer, Integer> cnt = new HashMap<>();
for (int x : nums) {
cnt.merge(x, 1, Integer::sum);
}
int k = nums.length;
for (int v : cnt.values()) {
k = Math.min(k, v);
}
for (;; --k) {
int ans = 0;
for (int v : cnt.values()) {
if (v / k < v % k) {
ans = 0;
break;
}
ans += (v + k) / (k + 1);
}
if (ans > 0) {
return ans;
}
}
}
}
```

### **C++**

```cpp

class Solution {
public:
int minGroupsForValidAssignment(vector<int>& nums) {
unordered_map<int, int> cnt;
for (int x : nums) {
cnt[x]++;
}
int k = 1e9;
for (auto& [_, v] : cnt) {
ans = min(ans, v);
}
for (;; --k) {
int ans = 0;
for (auto& [_, v] : cnt) {
if (v / k < v % k) {
ans = 0;
break;
}
ans += (v + k) / (k + 1);
}
if (ans) {
return ans;
}
}
}
};
```

### **Go**

```go
func minGroupsForValidAssignment(nums []int) int {
cnt := map[int]int{}
for _, x := range nums {
cnt[x]++
}
k := len(nums)
for _, v := range cnt {
k = min(k, v)
}
for ; ; k-- {
ans := 0
for _, v := range cnt {
if v/k < v%k {
ans = 0
break
}
ans += (v + k) / (k + 1)
}
if ans > 0 {
return ans
}
}
}

func min(a, b int) int {
if a < b {
return a
}
return b
}
```

### **TypeScript**

```ts
function minGroupsForValidAssignment(nums: number[]): number {
const cnt: Map<number, number> = new Map();
for (const x of nums) {
cnt.set(x, (cnt.get(x) || 0) + 1);
}
for (let k = Math.min(...cnt.values()); ; --k) {
let ans = 0;
for (const [_, v] of cnt) {
if (((v / k) | 0) < v % k) {
ans = 0;
break;
}
ans += Math.ceil(v / (k + 1));
}
if (ans) {
return ans;
}
}
}
```

### **Rust**

```rust
use std::collections::HashMap;

impl Solution {
pub fn min_groups_for_valid_assignment(nums: Vec<i32>) -> i32 {
let mut cnt: HashMap<i32, i32> = HashMap::new();

for x in nums.iter() {
let count = cnt.entry(*x).or_insert(0);
*count += 1;
}

let mut k = i32::MAX;

for &v in cnt.values() {
k = k.min(v);
}

for k in (1..=k).rev() {
let mut ans = 0;

for &v in cnt.values() {
if v / k < v % k {
ans = 0;
break;
}

ans += (v + k) / (k + 1);
}

if ans > 0 {
return ans;
}
}

0
}
}
```

### **...**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,193 @@ Hence, the answer is 4.</pre>

## Solutions

**Solution 1: Hash Table + Enumeration**

We use a hash table $cnt$ to count the number of occurrences of each number in the array $nums$. Let $k$ be the minimum value of the number of occurrences, and then we can enumerate the size of the groups in the range $[k,..1]$. Since the difference in size between each group is not more than $1$, the group size can be either $k$ or $k+1$.

For the current group size $k$ being enumerated, we traverse each occurrence $v$ in the hash table. If $\lfloor \frac{v}{k} \rfloor < v \bmod k$, it means that we cannot divide the occurrence $v$ into $k$ or $k+1$ groups with the same value, so we can skip this group size $k$ directly. Otherwise, it means that we can form groups, and we only need to form as many groups of size $k+1$ as possible to ensure the minimum number of groups. Therefore, we can divide $v$ numbers into $\lceil \frac{v}{k+1} \rceil$ groups and add them to the current enumerated answer. Since we enumerate $k$ from large to small, as long as we find a valid grouping scheme, it must be optimal.

The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $nums$.

<!-- tabs:start -->

### **Python3**

```python

class Solution:
def minGroupsForValidAssignment(self, nums: List[int]) -> int:
cnt = Counter(nums)
for k in range(min(cnt.values()), 0, -1):
ans = 0
for v in cnt.values():
if v // k < v % k:
ans = 0
break
ans += (v + k) // (k + 1)
if ans:
return ans
```

### **Java**

```java

class Solution {
public int minGroupsForValidAssignment(int[] nums) {
Map<Integer, Integer> cnt = new HashMap<>();
for (int x : nums) {
cnt.merge(x, 1, Integer::sum);
}
int k = nums.length;
for (int v : cnt.values()) {
k = Math.min(k, v);
}
for (;; --k) {
int ans = 0;
for (int v : cnt.values()) {
if (v / k < v % k) {
ans = 0;
break;
}
ans += (v + k) / (k + 1);
}
if (ans > 0) {
return ans;
}
}
}
}
```

### **C++**

```cpp

class Solution {
public:
int minGroupsForValidAssignment(vector<int>& nums) {
unordered_map<int, int> cnt;
for (int x : nums) {
cnt[x]++;
}
int k = 1e9;
for (auto& [_, v] : cnt) {
ans = min(ans, v);
}
for (;; --k) {
int ans = 0;
for (auto& [_, v] : cnt) {
if (v / k < v % k) {
ans = 0;
break;
}
ans += (v + k) / (k + 1);
}
if (ans) {
return ans;
}
}
}
};
```

### **Go**

```go
func minGroupsForValidAssignment(nums []int) int {
cnt := map[int]int{}
for _, x := range nums {
cnt[x]++
}
k := len(nums)
for _, v := range cnt {
k = min(k, v)
}
for ; ; k-- {
ans := 0
for _, v := range cnt {
if v/k < v%k {
ans = 0
break
}
ans += (v + k) / (k + 1)
}
if ans > 0 {
return ans
}
}
}

func min(a, b int) int {
if a < b {
return a
}
return b
}
```

### **TypeScript**

```ts
function minGroupsForValidAssignment(nums: number[]): number {
const cnt: Map<number, number> = new Map();
for (const x of nums) {
cnt.set(x, (cnt.get(x) || 0) + 1);
}
for (let k = Math.min(...cnt.values()); ; --k) {
let ans = 0;
for (const [_, v] of cnt) {
if (((v / k) | 0) < v % k) {
ans = 0;
break;
}
ans += Math.ceil(v / (k + 1));
}
if (ans) {
return ans;
}
}
}
```

### **Rust**

```rust
use std::collections::HashMap;

impl Solution {
pub fn min_groups_for_valid_assignment(nums: Vec<i32>) -> i32 {
let mut cnt: HashMap<i32, i32> = HashMap::new();

for x in nums.iter() {
let count = cnt.entry(*x).or_insert(0);
*count += 1;
}

let mut k = i32::MAX;

for &v in cnt.values() {
k = k.min(v);
}

for k in (1..=k).rev() {
let mut ans = 0;

for &v in cnt.values() {
if v / k < v % k {
ans = 0;
break;
}

ans += (v + k) / (k + 1);
}

if ans > 0 {
return ans;
}
}

0
}
}
```

### **...**
Expand Down
Loading