Algoritmo ganancioso: números monotonicamente crescentes

Mudou para um novo tema de tipografia, haha, como você se sente?

Aviso: alguns amigos gravadores disseram que muitas vezes não veem artigos diários. Agora, a conta oficial não é recomendada de acordo com o horário de envio, mas fica fora de ordem de acordo com algumas regras, então você pode ter seguido o "Código de Registro Aleatório" e nunca ter visto o artigo. Recomenda-se definir uma estrela para "Código Caprice". Após definir a estrela, ela será empurrada de acordo com a hora da postagem todos os dias. Carl envia regularmente às 8:35 todos os dias, oh pontual!

738. Números que aumentam monotonicamente
Dado um inteiro não negativo N, encontre o maior inteiro menor ou igual a N, e esse inteiro precisa satisfazer que os números em cada dígito estão aumentando monotonicamente.

(Se e somente se os números xey de cada dígito adjacente satisfizerem x <= y, chamamos esse número inteiro de aumento monotônico.)

Exemplo 1:
Entrada: N = 10
Saída: 9

Exemplo 2:
Entrada: N = 1234
Saída: 1234

Exemplo 3:
Entrada: N = 332
Saída: 299

Explicação: N é um número inteiro no intervalo de [0, 10 ^ 9].

A ideia de
uma solução violenta
é muito simples, então a primeira coisa a se pensar é uma solução violenta. Deixe-me mencionar uma onda de violência. O resultado é, naturalmente, horas extras!

código mostrado abaixo:


class Solution {
private:
    bool checkNum(int num) {
        int max = 10;
        while (num) {
            int t = num % 10;
            if (max >= t) max = t;
            else return false;
            num = num / 10;
        }
        return true;
    }
public:
    int monotoneIncreasingDigits(int N) {
        for (int i = N; i > 0; i--) {
            if (checkNum(i)) return i;
        }
        return 0;
    }
};
  • Complexidade de tempo: O (n * m) m é o comprimento do número de n
  • Complexidade do espaço: O (1) O problema de
    algoritmo guloso
    requer o maior número inteiro crescente monotonicamente menor ou igual a N, então tome um número de dois dígitos como exemplo.

Por exemplo: 98, uma vez que strNum [i-1]> strNum [i] ocorre (não aumentando monotonicamente), primeiro eu quero strNum [i-1] -, e então strNum [i] é 9 para que este número inteiro seja 89, isto é, o maior número inteiro monotonicamente crescente menor que 98.

Se você pensar sobre isso com clareza, essa questão será mais fácil de lidar.

Ótimo local: no caso de strNum [i-1]> strNum [i], deixe strNum [i-1] - e, em seguida, strNum [i] a 9 para garantir que esses dois bits se tornem o maior número inteiro monotonicamente crescente .

Ótimo global: obtenha o maior número inteiro monotonicamente crescente menor ou igual a N.

Mas aqui o ótimo local é derivado do ótimo global, e outras condições são necessárias, ou seja, a ordem de passagem e a marca a partir da qual o bit começa a ser alterado para 9.

É para atravessar da frente para trás ou de trás para a frente?

Se você atravessar da frente para trás, se strNum [i-1]> strNum [i] for encontrado, deixe strNum [i-1] subtrair um, mas se strNum [i-1] for subtraído por um, pode ser menor que strNum [i-2].

Isso é um pouco abstrato, por exemplo, o número: 332, se você percorrer da frente para trás, ele se torna 329. Nesse momento, 2 é menor que os 3 primeiros e o resultado real deve ser 299.

Portanto, percorrer da frente para trás mudará os resultados que foram percorridos!

Em seguida, percorrendo de trás para a frente, você pode reutilizar o resultado da última comparação. O valor de 332 da travessia de trás para a frente muda para: 332 -> 329 -> 299

Depois de determinar a ordem de travessia, o ótimo local pode ser apresentado ao global neste momento, e nenhum contra-exemplo pode ser encontrado, tente ser ganancioso.

O código C ++ é o seguinte:


class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(N);
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        int flag = strNum.size();
        for (int i = strNum.size() - 1; i > 0; i--) {
            if (strNum[i - 1] > strNum[i] ) {
                flag = i;
                strNum[i - 1]--;
            }
        }
        for (int i = flag; i < strNum.size(); i++) {
            strNum[i] = '9';
        }
        return stoi(strNum);
    }
};
  • Complexidade de tempo: O (n) n é o comprimento do número
  • Complexidade do espaço: O (n) requer uma string e é mais conveniente converter em uma operação de string.
    Para resumir
    esta questão, basta pensar em um exemplo claro, como 98. Assim que strNum [i-1]> strNum [i] ocorre (não aumentando monotonicamente) ), primeiro quero subtrair um de strNum [i-1] e atribuir 9 a strNum [i], de modo que o inteiro seja 89. Você pode naturalmente pensar na solução gananciosa correspondente.

Pensando na ganância, devemos também considerar a ordem de travessia.Somente percorrendo de trás para a frente os resultados da última comparação podem ser reutilizados.

Quando o código final é implementado, algumas habilidades também são necessárias, como usar uma bandeira para marcar onde começar a atribuição de 9.

Aprenda o algoritmo passo a passo e procure por "Code Random Record"!

Acho que você gosta

Origin blog.51cto.com/15069438/2576225
Recomendado
Clasificación