删除k个数字使剩下数字最小(大)

本文介绍了一种使用贪心算法优化数字序列的方法,通过删除指定数量的数字使剩余序列达到最小或最大值。算法扫描序列,根据目标(求最小或最大值),决定删除连续递增或递减序列的末尾数字。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如:1593121212去掉3个数,剩下1121212最小。
思路如下:
删除k个,可以采用贪心算法,每次删除1个
那么每次删哪一个呢?

  • 若N<2,那就不用纠结了,因为最多只有一个选择
  • 若N>=2,则该整数可以写成XabY,X,Y分别是前缀和后缀,长度可以为0. a,b是相邻的两个数字,且a在b的左边。我们面临的选择就是删除a还是删除b的问题。若删除a,删除后变为XbY; 若删除b,删除后变为XaY.
    (1) 若a ≠ \ne ̸=b,为了让剩下的部分最小,显然我们应该倾向于把a,b中的较大者删掉. 即若a<b, 倾向于删除b; 若a>b,倾向于删除a.
    (2) 若a=b, 删除a和删除b是等价的,我们跳过a,比较b和它的后继,又变成问题(1)了。

此时我们已经能看出:
要求剩下的数字最小,从左向右扫描,找出连续的非严格递增串,删除最后一个

要求剩下的数字最大,从左向右扫描,找出连续的非严格递减串,删除最后一个。

核心代码如下:

    public static int delKDigits(int number, int k, int max_or_min) {
        final int GET_MIN = 0;
        final int GET_MAX = 1;
        int[] digits = getDigits(number);
        for (int i = 0; i < k; i++) {
            int newLength = digits.length - 1;
            int[] digitsNew = new int[newLength];
            int j = 0;
            int delIndex = -1;
            switch (max_or_min) {
                case GET_MIN:
                    while (j < newLength - 1 && digits[j] <= digits[j + 1])
                        j++;
                    delIndex = j;
                    break;
                case GET_MAX:
                    while (j < newLength - 1 && digits[j] >= digits[j + 1])
                        j++;
                    delIndex = j;
                    break;
                default:
                    throw new IllegalArgumentException(
                            "max_or_in can only be either " + GET_MAX + "or " + GET_MIN + "!"
                    );
            }
            
            int n = 0;
            for (int m =0;m < digits.length;m++) {
                if (m != delIndex) {
                    digitsNew[n++] = digits[m];
                }
            }
            digits = digitsNew;
        }
        int result = getInt(digits);
        return result;
    }

完整代码可在我的github上下载.

```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <ctype.h> // 包含处理字符类型 // 定义一个结构体存储数字字符串和移除的位数 typedef struct { char* num_str; int k; } NumAndK; // 辅助函数,判断一个字符是否是数字 bool is_digit(char c) { return c >= '0' && c <= '9'; } // 辅助函数,获取字符串中数字部分的小 size_t get_num_length(const char* str) { size_t len = strlen(str); for (size_t i = 0; i < len; ++i) { if (!is_digit(str[i])) break; } return i; } // 辅助函数,从字符串中移除指定位置的字符 void remove_char(char* str, size_t index) { if (index < get_num_length(str)) { memmove(str + index, str + index + 1, strlen(str) - index); } else { printf("Error: Index out of bounds.\n"); } } // 主函数,移除指定数量的数字字符 char* remove_k_digits(NumAndK* num_and_k) { char* num_str = num_and_k->num_str; int k = num_and_k->k; // 获取原始数字串长度 size_t orig_len = strlen(num_str); // 检查是否需要移除所有数字 if (k >= orig_len) { free(num_str); num_and_k->num_str = strdup(""); return num_and_k->num_str; } // 初始化新字符串,用于存放剩余的数字 char* new_str = (char*)malloc(strlen(num_str) + 1); memset(new_str, 0, strlen(num_str) + 1); // 找到第一个数字字符作为分界点 size_t start_index = 0; for (; start_index < orig_len && is_digit(num_str[start_index]); start_index++) {} // 从第二个字符开始遍历,移除非数字字符前k个数字 for (size_t i = 1; i < start_index && k > 0; i++) { if (is_digit(num_str[i])) { remove_char(num_str, i - 1); // 移除数字 k--; } } // 把剩余的数字复制到新字符串 strncpy(new_str, num_str + start_index, orig_len - start_index); new_str[strlen(new_str)] = '\0'; // 添加终止符 // 返回新的数字字符串 num_and_k->num_str = new_str; return new_str; } int main() { NumAndK num; num.num_str = "1432219"; num.k = 2; char* result = remove_k_digits(&num); printf("After removing %d digits: %s\n", num.k, result); free(result); // 释放内存 return 0; } ``` 这段代码定义了一个名为`remove_k_digits`的函数,接收一个包含数字字符串和移除位数的结构体实例。它通过找到第一个数字字符作为分界点,然后移除非数字字符之前指定数量的数字字符,以求得剩余数字最小一个。如果需要移除的所有数字都已被移除,返回空字符串表示剩余0。在`main`函数中测试该功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值