carloscn / structstudy

Leetcode daily trainning by using C/C++/RUST programming.
4 stars 1 forks source link

leetcode1984: Minimum Difference Between Highest and Lowest of K Scores #317

Open carloscn opened 1 year ago

carloscn commented 1 year ago

Description

You are given a 0-indexed integer array nums, where nums[i] represents the score of the ith student. You are also given an integer k.

Pick the scores of any k students from the array so that the difference between the highest and the lowest of the k scores is minimized.

Return the minimum possible difference.

Example 1:

Input: nums = [90], k = 1 Output: 0 Explanation: There is one way to pick score(s) of one student:

Example 2:

Input: nums = [9,4,1,7], k = 2 Output: 2 Explanation: There are six ways to pick score(s) of two students:

Constraints:

1 <= k <= nums.length <= 1000 0 <= nums[i] <= 105

carloscn commented 1 year ago

Analysis

要打印一个数组的所有子集,可以使用位运算的方法来生成所有可能的子集。数组中的每个元素可以被表示为二进制位的一位,其中 1 表示该元素被选中,0 表示未选中。通过迭代所有可能的位组合,可以生成所有子集。

以下是使用 C 语言的代码示例来实现这一点:

#include <stdio.h>

void printSubset(int arr[], int size, int mask) {
    printf("{ ");
    int firstElement = 1;

    for (int i = 0; i < size; i++) {
        if (mask & (1 << i)) {
            if (!firstElement) {
                printf(", ");
            }
            printf("%d", arr[i]);
            firstElement = 0;
        }
    }

    printf(" }\n");
}

void generateSubsets(int arr[], int size) {
    int numSubsets = 1 << size;  // 2^size
    for (int i = 0; i < numSubsets; i++) {
        printSubset(arr, size, i);
    }
}

int main() {
    int arr[] = {1, 2, 3};
    int size = sizeof(arr) / sizeof(arr[0]);

    generateSubsets(arr, size);

    return 0;
}

在这个代码中,generateSubsets 函数通过迭代从 0 到 2^size - 1 的所有数字来生成位掩码,然后调用 printSubset 函数打印对应的子集。printSubset 函数根据位掩码打印数组中相应位为 1 的元素。

请注意,这个方法适用于数组元素数量较小的情况。对于更大的数组,可能会导致子集数量过多,消耗大量时间和内存。

如果数组比较长,生成所有子集可能会导致时间和内存的巨大开销,因为子集数量会呈指数级增长。在处理较大的数组时,你可以考虑使用递归的方法来生成子集,这样可以避免显式地生成和存储所有子集。

以下是一个使用递归方法生成子集的 C 代码示例:

#include <stdio.h>

void printSubset(int arr[], int subset[], int size) {
    printf("{ ");
    int firstElement = 1;

    for (int i = 0; i < size; i++) {
        if (subset[i]) {
            if (!firstElement) {
                printf(", ");
            }
            printf("%d", arr[i]);
            firstElement = 0;
        }
    }

    printf(" }\n");
}

void generateSubsetsRec(int arr[], int subset[], int idx, int size) {
    if (idx == size) {
        printSubset(arr, subset, size);
        return;
    }

    subset[idx] = 0;
    generateSubsetsRec(arr, subset, idx + 1, size);

    subset[idx] = 1;
    generateSubsetsRec(arr, subset, idx + 1, size);
}

void generateSubsets(int arr[], int size) {
    int subset[size];
    generateSubsetsRec(arr, subset, 0, size);
}

int main() {
    int arr[] = {1, 2, 3};
    int size = sizeof(arr) / sizeof(arr[0]);

    generateSubsets(arr, size);

    return 0;
}

在这个代码中,generateSubsetsRec 函数使用递归来生成所有子集。对于数组中的每个元素,它有两个选择:选中或不选中。通过递归调用,它在每一步都考虑这两个选择,直到考虑完所有元素为止。

这种方法相对于生成所有可能的位掩码要更节省内存,因为它只在递归树上保持了一个子集数组。然而,由于递归的性质,对于较大的数组仍然可能导致栈溢出或性能下降。在实际应用中,可能需要根据情况对递归深度和内存使用进行优化。

pub fn minimum_difference(nums: Vec<i32>, k: i32) -> i32
{
    if nums.len() < 2 || k == 0 {
        return 0;
    }

    let mut ret:i32 = i32::MAX;
    let sub_array_len:i32 = 1 << nums.len();
    let mut s_v:Vec<i32> = vec![];

    for mask in 0..sub_array_len {
        for i in 0..nums.len() as i32 {
            if (mask & (1 << i)) != 0 {
                s_v.push(nums[i as usize]);
            }
        }
        if s_v.len() == 2 {
            ret = ret.min(i32::abs(s_v[0] - s_v[1]));
        }
        s_v.clear();
    }

    return ret;
}
carloscn commented 1 year ago

Code

https://review.gerrithub.io/c/carloscn/structstudy/+/1168161 https://github.com/carloscn/structstudy/commit/ec3cd81c0cf0094e91b28e034fcdf6d2c8bdf359