[Leetcode Road to Brushing Questions] Oferta Jianzhi (4) - Dividir e Conquistar + Algoritmo de Classificação + Programação Dinâmica

8 algoritmo de divisão e conquista

8.1 [Recursão] Oferta do Ponteiro de Espada 07 - Reconstruir Árvore Binária

https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/

  A travessia de pré-ordem é sobre a raiz, e a travessia em ordem é a raiz esquerda e direita, o que significa que o primeiro nó da travessia de pré-ordem é o nó raiz de toda a árvore. Siga este nó para encontrar seu posição na travessia em ordem. É in_root, então o lado esquerdo de in_root está na subárvore esquerda e o lado direito está na subárvore direita, para que você possa saber quantos nós existem na subárvore esquerda, e em seguida, vá para o percurso de pré-ordem para encontrar o ponto de divisão das subárvores esquerda e direita, dividido em Para as partes esquerda e direita, repita o processo acima respectivamente, encontre o primeiro nó raiz de cada parte e prossiga para baixo em sequência até o os limites das subárvores esquerda e direita se sobrepõem no final e a reconstrução da árvore binária é concluída.

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
private:
    unordered_map<int,int> hash_table;
public:
    TreeNode* subTree(vector<int>& preorder, vector<int>& inorder, int pre_l, int pre_r, int in_l, int in_r)
    {
    
    
        if(pre_l > pre_r) return nullptr;
        //找到根节点,计算左子树的节点数
        int pre_root = pre_l;
        int in_root = hash_table[preorder[pre_l]];
        int sub_l = in_root - in_l;
        //开始生成root
        TreeNode* root = new TreeNode(preorder[pre_l]);
        //对于左子树而言,前序遍历的[左边界+1,左边界+左子树节点数]即为中序遍历的[左边界,根节点-1]
        root->left = subTree(preorder, inorder, pre_l+1, pre_l+sub_l, in_l, in_root-1);
        //对于右子树而言,前序遍历的[左边界+左子树节点数+1,右边界]即为中序遍历的[根节点+1,右边界]
        root->right = subTree(preorder, inorder, pre_l+sub_l+1, pre_r, in_root+1, in_r);
        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {
    
    
        int n = inorder.size();
        for(int i=0;i<n;i++)
        {
    
    
            hash_table[inorder[i]] = i;
        }
        return subTree(preorder, inorder, 0, n-1, 0, n-1);
    }
};

8.2 [Recursivo] [Quick Power] Jianzhi Oferta 16 - a potência inteira do valor

https://leetcode.cn/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/description/

  Este problema pode ser resolvido com potência rápida. A ideia específica é desmontar a potência de acordo com o binário e calculá-la separadamente. Aqui está um exemplo: Suponha que eu queira calcular x 10 x^ {10}x10 , porque a representação binária de 10 é 1010, entãox 10 = x 2 0 ∗ 0 ∗ x 2 1 ∗ 1 ∗ x 2 2 ∗ 0 ∗ x 2 3 ∗ 1 x^{10}=x^{2^0 * 0}*x^{2^1*1}*x^{2^2*0}*x^{2^3*1}x10=x200x21 *1x22 *0x23 *1pode ser considerado como crescente em ordem de acordo com a potência de 2 de x. Basta verificar se o binário correspondente a esta potência é 1.

class Solution {
    
    
public:
    double myPow(double x, int n) {
    
    
        if(x==1 || n==0) return 1;
        if(x==0) return 0;

        double ans = 1;
        long num = n;
        if(n<0)
        {
    
    
            num = -num;
            x = 1/x;
        }
        while(num)
        {
    
    
            if(num & 1) ans *= x;
            x *= x;
            num >>= 1;
        }
        return ans;
    }
};

8.3 [Recursão] Espada refere-se à Oferta 33 - sequência de travessia pós-ordem da árvore de pesquisa binária

https://leetcode.cn/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof

  A característica da travessia pós-ordem é visitar primeiro a subárvore esquerda, depois a subárvore direita e finalmente o nó raiz, então o último elemento deve ser o nó raiz, e a característica da árvore de pesquisa binária é que a subárvore esquerda <raiz nó <subárvore direita, então nós A matriz pode ser dividida em duas partes de acordo com o valor do nó raiz e, em seguida, julgar se está em conformidade com as características da árvore de pesquisa binária e repetir o processo acima até que todos os casos sejam julgados.

class Solution {
    
    
public:
    bool dfs(vector<int>& postorder, int left, int right)
    {
    
    
        if(left >= right) return true;

        int i = left;
        while(postorder[i]<postorder[right])
        {
    
    
            i++;
        }
        int mid = i;
        while(postorder[i]>postorder[right])
        {
    
    
            i++;
        }
        return i==right & dfs(postorder,left,mid-1) & dfs(postorder,mid,right-1);
    }
    bool verifyPostorder(vector<int>& postorder)
    {
    
    
        return dfs(postorder,0,postorder.size()-1);
    }
};

8.4 [Recursão] [Dividir e Conquistar] Oferta do Ponteiro de Espada 17 - Imprima os n dígitos de 1 ao maior

https://leetcode.cn/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof

  Como esta questão especifica que o array é do tipo int, não há necessidade de considerar o problema de números inteiros grandes, e ele pode ser resolvido por violência direta. Porém, se for um número inteiro grande, a ideia de dividir e conquistar a recursão precisa ser adotada, principalmente da seguinte forma:

(1) O primeiro nível de travessia é n, considerando que os números gerados são de 1 dígito, 2 dígitos, 3 dígitos...n dígitos;

(2) O segundo nível de travessia, percorrendo respectivamente o número de cada dígito, exceto o primeiro dígito é 1-9, o restante é 0-9.

class Solution {
    
    
public:
    vector<int> printNumbers(int n) {
    
    
        int cnt = pow(10,n);
        vector<int> ans;
        for(int i=1;i<cnt;i++)
        {
    
    
            ans.push_back(i);
        }
        return ans;
    }
};

8.5 [Mesclar e Classificar] [Dividir e Conquistar] Oferta do Ponteiro de Espada 51 - Pares invertidos na matriz

https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof

  Bem escrito por esse cara! ( https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solutions/622496/jian-zhi-offer-51-shu-zu-zhong-de-ni-xu -pvn2h )

class Solution {
    
    
public:
    int merge_sort(int left, int right, vector<int>& nums, vector<int>& tmp)
    {
    
    
        if(left >= right) return 0;
        int mid = (left + right) / 2;
        int res = merge_sort(left, mid, nums, tmp) + merge_sort(mid+1, right, nums, tmp);
        
        int i = left, j = mid + 1;
        for(int k=left;k<=right;k++)
        {
    
    
            tmp[k] = nums[k];
        }
        for(int k=left;k<=right;k++)
        {
    
     
            if(i == mid+1) nums[k] = tmp[j++];
            else if(j == right+1 || tmp[i] <= tmp[j]) nums[k] = tmp[i++];
            else
            {
    
    
                nums[k] = tmp[j++];
                res += mid - i + 1;
            }
        }
        return res;
    }

    int reversePairs(vector<int>& nums)
    {
    
    
        vector<int> tmp(nums.size());
        return merge_sort(0, nums.size()-1, nums, tmp);
    }
};

9 tipo

9.1 [Bubble Sort] Jianzhi Oferta 45 - Organize a matriz no menor número

https://leetcode.cn/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof

  Esta questão pode ser considerada uma classificação por bolha, mas o objeto é uma string, precisamos encontrar a maior string nele e colocá-la no final da string, como "32" e "3", porque " 323"<"332", então "32"<"3", então "3" deve ser colocado depois de "32" e use esta ideia de classificação para resolver o problema.

class Solution {
    
    
public:
    string minNumber(vector<int>& nums) 
    {
    
    
        for(int i=nums.size()-1;i>0;i--)
        {
    
    
            for(int j=0;j<i;j++)
            {
    
    
                if(string_sort(nums[j],nums[j+1]))
                {
    
    
                    swap(nums[j],nums[j+1]);
                }
            }
        }
        string ans = "";
        for(int i=0;i<nums.size();i++)
        {
    
    
            ans += to_string(nums[i]);
        }
        return ans;
    }
    
    bool string_sort(int num1, int num2)
    {
    
    
        string s1 = to_string(num1) + to_string(num2);
        string s2 = to_string(num2) + to_string(num1);
        if(s1>s2) return true;
        else return false;
    }
};

9.2 [Classificação] Jianzhi Oferta 61 - Straight in Poker

https://leetcode.cn/problems/bu-ke-pai-zhong-de-shun-zi-lcof

  Esta questão não é difícil, basta pensar com clareza nas condições de julgamento de Shunzi, principalmente nos seguintes aspectos:

(1) Entre os cinco números, não pode haver números repetidos além de 0, caso contrário, definitivamente não é uma sequência;

(2) Encontre os valores máximo e mínimo entre os cinco números, veja quantos números estão faltando entre esses dois números, registre-os como lacuna e, em seguida, calcule o número de 0s entre os cinco números, registre-os como zero_num, se gap <= zero_num, significa que o número 0 pode preencher o número que falta, caso contrário, definitivamente não é uma sequência.

class Solution {
    
    
public:
    bool isStraight(vector<int>& nums) {
    
    
        int arr[14] = {
    
    0};
        int max_num = 0, min_num = 14, zero_num = 0;
        for(int i=0;i<5;i++)
        {
    
    
            if(nums[i]==0) zero_num++;
            else
            {
    
    
                if(arr[nums[i]]) return false;
                else
                {
    
    
                    arr[nums[i]] = 1;
                    min_num = min(min_num, nums[i]);
                    max_num = max(max_num, nums[i]);
                }
            }
        }
        int gap = 0;
        for(int i=min_num;i<max_num;i++)
        {
    
    
            if(arr[i]!=1) gap++;
        }
        if(gap <= zero_num) return true;
        else return false;
    }
};

9.3 [Classificação de heap] Jianzhi Oferta 40 - o menor número k

https://leetcode.cn/problems/zui-xiao-de-kge-shu-lcof

  Método 1: Use classificar para classificar diretamente e, em seguida, selecione os k números principais.

  Método 2: Use classificação de heap, classificação de heap, usando o heap raiz grande, primeiro armazene os primeiros k números no heap raiz grande e compare os números subsequentes com o topo do heap raiz grande, se for menor que o topo, atualize o heap raiz grande e, finalmente, coloque o heap raiz grande. Os números no vetor são retornados como resposta.

//方法一:直接排序
class Solution {
    
    
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
    
    
        sort(arr.begin(),arr.end());
        vector<int> ans;
        for(int i=0;i<k;i++)
        {
    
    
            ans.push_back(arr[i]);
        }
        return ans;
    }
};
//方法二:堆排序
class Solution {
    
    
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
    
    
        vector<int> ans;
        if(k == 0) return ans;

        priority_queue<int, vector<int>, less<int>> max_stack;
        //把前k个数字存入大根堆
        for(int i=0;i<k;i++)
        {
    
    
            max_stack.push(arr[i]);
        }
        //依次和大根堆的top比较,如果比top小就更新大根堆
        for(int j=k;j<arr.size();j++)
        {
    
    
            if(arr[j] < max_stack.top())
            {
    
    
                max_stack.pop();
                max_stack.push(arr[j]);
            }
        }
        //把大根堆中的数字存入vector中作为答案返回
        while(k--)
        {
    
    
            ans.push_back(max_stack.top());
            max_stack.pop();
        }
        return ans;
    }
};

9.4 [Heap Sort] [Priority Queue] Apontando para a oferta 41 - Mediana no fluxo de dados

https://leetcode.cn/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof

  Se esta questão classificar todos os números diretamente, ela será executada no final. Na verdade, desde que possamos encontrar dois números ou um número no meio de todo o fluxo de dados toda vez que a função findMedian for executada, podemos considerar usando classificação de heap. Mantenha uma pilha raiz grande e uma pilha raiz pequena ao mesmo tempo, divida o número no fluxo de dados em duas partes e também garanta que o topo da pilha raiz grande seja menor do que o topo da raiz pequena pilha, de modo que a mediana final seja pequena. O topo da pilha raiz, ou a média do topo da pilha raiz grande e da pilha raiz pequena, é construído da seguinte forma:

  • Se o tamanho do heap raiz grande e do heap raiz pequeno forem iguais, então o número de add é adicionado ao heap raiz grande neste momento e, em seguida, o topo do heap raiz grande é inserido no heap raiz pequeno para certifique-se de que o tamanho do heap raiz grande<=o tamanho do heap raiz pequeno;
  • Se o tamanho do heap raiz grande e do heap raiz pequeno forem diferentes, então o número de adição é adicionado ao heap raiz pequeno neste momento e, em seguida, o topo do heap raiz pequeno é inserido no heap raiz grande para garantir que o tamanho do heap raiz pequeno<=o tamanho do heap raiz grande;
  • Ao executar a função findMedian, verifique se os tamanhos do heap raiz grande e do heap raiz pequeno são iguais. Se forem iguais, a mediana é a soma dos elementos superiores e calcula a média. Se não forem iguais, a mediana é o tamanho do pequeno heap raiz.
class MedianFinder {
    
    
public:
    /** initialize your data structure here. */
    priority_queue<int, vector<int>, greater<int>> min_stack;
    priority_queue<int, vector<int>, less<int>> max_stack;

    MedianFinder() {
    
    

    }
    
    void addNum(int num) {
    
    
        //如果大根堆和小根堆的size一样,那么此时add的num就加入大根堆,然后把大根堆的top插入到小根堆中,保证大根堆的size<=小根堆的size
        if(min_stack.size() == max_stack.size())
        {
    
    
            max_stack.push(num);
            min_stack.push(max_stack.top());
            max_stack.pop();
        }
        //如果大根堆和小根堆的size不一样,那么此时add的num就加入小根堆,然后把小根堆的top插入到大根堆中,保证小根堆的size<=大根堆的size
        else
        {
    
    
            min_stack.push(num);
            max_stack.push(min_stack.top());
            min_stack.pop();
        }
    }
    //执行findMedian函数时,看看此时大根堆和小根堆的size是否相等,如果相等的话,中位数就是各自取top元素相加取平均,如果不相等,那么中位数就是小根堆的top
    double findMedian() {
    
    
        if(min_stack.size() == max_stack.size())
        {
    
    
            return (max_stack.top() + min_stack.top()) / 2.0;
        }
        else return min_stack.top();
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */

10 Programação Dinâmica

10.1 [Programação Dinâmica] [Tabela Hash] [DFS] Oferta do Ponteiro de Espada 10- I - Sequência de Fibonacci

https://leetcode.cn/problems/fei-bo-na-qi-shu-lie-lcof

  Se você usar programação dinâmica diretamente para esta questão, o tempo de execução será principalmente porque alguns números serão calculados repetidamente durante o processo de cálculo, então usamos uma tabela hash para armazenar os números calculados aqui, para que quando eles forem calculados novamente mais tarde, basta usar diretamente.

class Solution {
    
    
public:
    unordered_map<int,int> hash_table;
    int dfs(int n)
    {
    
    
        if(n == 0) return 0;
        else if(n == 1) return 1;
        else
        {
    
    
            if(hash_table.count(n)) return hash_table[n];
            else
            {
    
    
                int num1 = dfs(n-1) % 1000000007;
                int num2 = dfs(n-2) % 1000000007;
                hash_table[n] = (num1 + num2) % 1000000007;
                return hash_table[n];
            }
        }
    }
    int fib(int n) 
    {
    
    
        return dfs(n);
    }
};

10.2 [Programação Dinâmica] [Tabela Hash] [DFS] Oferta do Ponteiro de Espada 10- II - Passos de salto de sapo

https://leetcode.cn/problems/qing-wa-tiao-tai-jie-wen-ti-lcof

  Este tópico é a sequência de Fibonacci deformada. Aqui, uma tabela hash é usada para armazenar os números que foram calculados, para que possam ser usados ​​diretamente quando forem calculados novamente mais tarde.

class Solution {
    
    
public:
    unordered_map<int,int> hash_table;
    int dfs(int n)
    {
    
    
        if(n == 0) return 1;
        else if(n == 1) return 1;
        else
        {
    
    
            if(hash_table.count(n)) return hash_table[n];
            else
            {
    
    
                int num1 = dfs(n-1) % 1000000007;
                int num2 = dfs(n-2) % 1000000007;
                hash_table[n] = (num1 + num2) % 1000000007;
                return hash_table[n];
            }
        }
    }
    int numWays(int n) {
    
    
        return dfs(n);
    }
};

10.3 [Programação dinâmica] Espada refere-se à Oferta 63 - o lucro máximo das ações

https://leetcode.cn/problems/gu-piao-de-zui-da-li-run-lcof

  A solução para problemas de programação dinâmica é principalmente encontrar a equação de transição de estado. Para este problema, a transição de estado depende de haver ações em um determinado dia. Usamos isso como limite para definir a equação de transição de estado dp[i][ 2]:

(1) Não manteve ações nos dias anteriores

dp [i] [0] = max (dp [i − 1] [0], dp [i − 1] [1] + preços [i]) dp[i][0] = max(dp[i-1 ][0], dp[i-1][1] + preços[i])d p ​​[ eu ] [ 0 ]=x ( d p [ eu-1 ] [ 0 ] ,d p ​​[ eu-1 ] [ 1 ]+preços [ eu ] ) _ _

(2) Manter ações no dia anterior

dp [ i ] [ 1 ] = max ( dp [ i − 1 ] [ 1 ] , 0 − preços [ i ] ) dp[i][1] = max(dp[i-1][1], 0 - preços [eu])d p ​​[ eu ] [ 1 ]=x ( d p [ eu-1 ] [ 1 ] ,0-preços [ eu ] ) _ _

  Ao mesmo tempo, também é necessário prever a situação em que os preços estão vazios e retornar 0 neste momento, pois os dois elementos do dp são chamados repetidamente, então o código é substituído diretamente por duas variáveis.

class Solution {
    
    
public:
    int maxProfit(vector<int>& prices) {
    
    
        if(!prices.size()) return 0;
        int dp_0 = 0, dp_1 = -prices[0];
        for(int i=1;i<prices.size();i++)
        {
    
    
            dp_0 = max(dp_0, dp_1 + prices[i]);
            dp_1 = max(dp_1, 0 - prices[i]);
        }
        return dp_0;
    }
};

10.4 [Programação Dinâmica] [Dividir e Conquistar] A espada refere-se à Oferta 42 - a soma máxima de submatrizes consecutivas

https://leetcode.cn/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof

  Esta questão usa uma pequena ideia de dividir e conquistar, assumindo que o comprimento do array agora é nnn , a soma máxima de submatrizes consecutivas éf ( n ) f(n)f ( n ),那么f ( n ) = max ( f ( n − 1 ) + nums [ i ] , num [ i ] ) f (n) = max (f (n-1) + nums [i], num [eu])f ( n )=x ( f ( n-1 )+n você m s [ eu ] ,n você m [ i ]) , o que significa que a maior soma é a primeiran − 1 n-1n-A maior soma de 1 número mais oiieu número, ou oiitheu numero a si mesmo, se for oiésimoPara o número i em si, é necessário encontrar a submatriz contínua a partir daqui e registrar o valor máximo no processo.

class Solution {
    
    
public:
    int maxSubArray(vector<int>& nums) {
    
    
        int pre = 0, max_seqsum = nums[0];
        for(int i=0;i<nums.size();i++)
        {
    
    
            pre = max(pre + nums[i], nums[i]);
            max_seqsum = max(max_seqsum, pre);
        }
        return max_seqsum;
    }
};

10.5 [Programação dinâmica] Espada refere-se à oferta 47 - o valor máximo do presente

https://leetcode.cn/problems/li-wu-de-zui-da-jie-zhi-lcof

  Na verdade, o valor máximo de cada local está relacionado apenas a dois estados, assumindo que o requisito atual seja valor [i] [j] valor[i][j]v a l u e [ i ] [ j ]的最大值,那么valor [ i ] [ j ] = max ( valor [ i ] [ j − 1 ] , valor [ i − 1 ] [ j ] ) + grade [ i ] [ j ] valor[i][j] = max(valor[i][j-1],valor[i-1][j]) + grade[i][j]v a l você e [ eu ] [ j ]=x ( v a l u e [ i ] [ j-1 ] ,v a l você e [ eu-1 ] [ j ])+g r i d [ i ] [ j ] , para conveniência da inicialização, o tamanho da matriz inicial é definido como( m + 1 ) ∗ ( n + 1 ) (m+1)*(n+1)( m+1 )( n+1 )

class Solution {
    
    
public:
    int maxValue(vector<vector<int>>& grid) 
    {
    
    
        int m = grid.size(), n = grid[0].size();
        int value[m+1][n+1];
        memset(value,0,sizeof(value));
        for(int i=0;i<m;i++)
        {
    
    
            for(int j=0;j<n;j++)
            {
    
    
                value[i+1][j+1] = max(value[i+1][j],value[i][j+1]) + grid[i][j];
            }
        }
        return value[m][n];
    }
};

Guess you like

Origin blog.csdn.net/qq_44528283/article/details/132571866