From 8bedd7a0ac1908adc4c5088cafb6d9d3b1ecdbc6 Mon Sep 17 00:00:00 2001 From: gameloader Date: Sat, 21 Sep 2024 21:39:53 +0800 Subject: [PATCH] leetcode update --- content/posts/leetcode.md | 66 +++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/content/posts/leetcode.md b/content/posts/leetcode.md index cc48069..3e735c2 100644 --- a/content/posts/leetcode.md +++ b/content/posts/leetcode.md @@ -13618,16 +13618,19 @@ private: ``` ## day206 2024-09-20 -### 214. Shortest Palindrome -You are given a string s. You can convert s to a + +### 214. Shortest Palindrome + +You are given a string s. You can convert s to a palindrome - by adding characters in front of it. +by adding characters in front of it. Return the shortest palindrome you can find by performing this transformation. ![092021GmdHWmTgR4](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/092021GmdHWmTgR4.png) ### 题解 + 本题是一道难题,但整体思路是比较简洁的,我们只能在字符串的前面添加字符来构造回文串,则以字符串开头作为起始的回文子字符串是不需要构造的,需要添加的只是回文子字符串后面的部分。(如aabaac,则aabaa是不需要做任何变动的,只需添加c),如果在字符串中间位置有一个回文串对于构造整个回文串影响不大(如acbcd,显然要构造回文串必须将cbcd反转一遍)。则解题思路为先找到以字符串开头为起始的原始字符串中的最长回文子串,再将该子串后面的字符串反转添加到字符串前面即得到目标字符串。 接下来要解决的问题是,如何得到以开头作为起始的最长回文子串有多长。如果我们将字符串逆序, 问题就变成了能找到的包含原始字符串开头和包含逆转后的字符串末尾的两个字符串中相同的子字符串最长有多长(如aabaac逆转后为caabaa则前一个字符串开头的aa和后一个字符串结尾的aa完全相同,则最长为2)。这是一个模式匹配的问题,如果熟悉kmp算法的话,就会发现这和kmp算法中next数组的含义非常相似,如果把原始字符串和逆转后的字符串连接在一起,就变成了求这个连接后的字符串的最长公共前后缀的长度问题,若字符串长度为n,则此问题即为求next\[n-1\]。 @@ -13640,20 +13643,21 @@ kmp算法的next的求法网上已经有很多讲解,以下面的情况为例 本题还可以使用滚动哈希来解决。即Rabin-Karp算法,这里不再讲解该算法,可参考下面的资料 -[Rabin-Karp算法](https://algo.itcharge.cn/06.String/02.String-Single-Pattern-Matching/02.String-Rabin-Karp/#_2-2-%E6%BB%9A%E5%8A%A8%E5%93%88%E5%B8%8C%E7%AE%97%E6%B3%95) +[Rabin-Karp算法](https://algo.itcharge.cn/06.String/02.String-Single-Pattern-Matching/02.String-Rabin-Karp/#_2-2-%E6%BB%9A%E5%8A%A8%E5%93%88%E5%B8%8C%E7%AE%97%E6%B3%95) ### 代码 -```cpp + +```cpp class Solution { public: string shortestPalindrome(string s) { string rev_s = s; reverse(rev_s.begin(), rev_s.end()); string temp = s + "#" + rev_s; - + int n = temp.length(); vector lps(n, 0); - + for (int i = 1, len = 0; i < n;) { if (temp[i] == temp[len]) { lps[i++] = ++len; @@ -13665,14 +13669,58 @@ public: } // 最长回文前缀的长度 int longest_palindrome_prefix = lps[n - 1]; - + // 需要反转并添加到前面的子串 string to_reverse = s.substr(longest_palindrome_prefix); reverse(to_reverse.begin(), to_reverse.end()); - + // 拼接并返回结果 return to_reverse + s; } }; ``` + +## day207 2024-09-21 + +### 386. Lexicographical Numbers + +Given an integer n, return all the numbers in the range [1, n] sorted in lexicographical order. + +You must write an algorithm that runs in O(n) time and uses O(1) extra space. + +![09219ROMuzHfztdy](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/09219ROMuzHfztdy.png) + +### 题解 + +本题要求将从1-n的数字按照字典序排列,要明确字典序的含义,即将数字视为字符串,从头开始遍历字符串,对每一位的字符,字符小(ascii码小,或者理解为一般意义上的字符顺序如a-z,0-9)的即在前面,短字符串和长字符串的前缀相同,则短字符串在前面。 + +在遍历这样的数字过程中相当于构造了一棵树,树的每一层都是0-9,如果还可以继续产生下一层则先产生下一层并遍历。对每一层的操作都是相同的因此可以使用递归解决。这里的层就是将原来的数字乘10后对个位进行遍历,看当前产生的新数字乘10是否小于n,小于n则可以产生新的一层。在每一层的操作为:遍历0-9,遍历每个数字时与原始数字相加构成新数字,判断新数字是否小于n,小于n则将新数字乘10判断是否小于n,小于n则递归调用层处理函数,将新数字乘10作为参数传递当作下一层的原始数字。 + +相当于固定0-9的顺序产生一棵生成树,对这棵多叉树进行后序遍历。 + +### 代码 + +```cpp +class Solution { +public: + vector lexicalOrder(int n) { + vector result; + for(int i=1;i<=9 && i<=n;i++){ + result.push_back(i); + if (i*10 <= n){ + layer(i*10, result, n); + } + } + return result; + } + void layer(int raw, vector& result, int target){ + for (int i=0; i<=9 && raw+i<=target; i++){ + result.push_back(raw+i); + if ((raw+i)*10 <= target){ + layer((raw+i)*10, result, target); + } + } + } +}; +```