1. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example:

Input: "babad"

Output: "bab"

Note: "aba" is also a valid answer.

Example:

Input: "cbbd"

Output: "bb"

https://leetcode.com/problems/longest-palindromic-substring/solution/

解题思路:其实就是求给定字符串中的最长回文。方法一是将原字符串逆置,然后找最长公共子串,但是这里有一个很容易犯的错误:

原因在于回文应该是原字符串中和逆字符串相对应的同一组,但是按照找最长公共子串匹配到的可能是两组数字。比如 abacdfgdcaba 中 按照逆置找公共子串找到的其实是 前面的abacd 和后面的dcaba,虽然倒着读的确一样但其实是两个字字串。所以在用这个方法时还要额外判断,如果我们找到的公共最长字串它们的索引在原字符串中是一致的则判定为回文,否则skip掉。

当然也可以Brute Force和dp来解决此问题,现在使用一种较简单的 Expand Around Center 方法:

import java.util.*;

public class LeetCode{
private static int lo,maxLen; public static void main(String[] args){
Scanner sc=new Scanner(System.in);
String input=sc.nextLine();
System.out.println(longestPalindrome(input));
} public static String longestPalindrome(String s){
    // 求长度的话,数组是直接调用length变量,String是调用 length() 方法
int len=s.length();
if(len<2)
return s;
for(int i=0;i<len-1;i++){
expandAroungCenter(s,i,i);
expandAroungCenter(s,i,i+1);
}
return s.substring(lo,lo+maxLen);
} public static void expandAroungCenter(String s, int left, int right){
    // 直接用String的charAt()方法,不需要再转为字符数组了
while(left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)){
left--;
right++;
}
if(maxLen<right-left-1){
lo=left+1;
maxLen=right-left-1;
}
}
}

尝试使用dp去解题,本来以为和求公共最长字串的dp相似,结果并非如此,耗了一番功夫,踩了几个坑才勉强解出。先是dp思想:

再上错误代码:

class Solution {
public String longestPalindrome(String s) {
int max_long=0;
int start_index=0;
boolean[][] dp=new boolean[s.length()][s.length()];
for(int i=0;i<s.length();i++){
dp[i][i]=true;
        dp[i][i+1]=s.charAt(i)==s.charAt(i+1);
} for(int i=0;i<s.length()-1;i++){
for(int j=i+1;j<s.length();j++){
if(j==i+1){
dp[i][j] = s.charAt(i)==s.charAt(j);
}else{
if(s.charAt(i)==s.charAt(j)){
dp[i][j]=dp[i+1][j-1];
}else{
dp[i][j]=false;
}
} if(dp[i][j]==true&&(j-i+1>max_long)){
max_long=j-i+1;
start_index=i;
}
}
} return s.substring(start_index, max_long);
}
}

上面的dp在于没有搞清楚dp的计算是自低向上的,即先求出最子问题的最优解再向上一层层计算,每层的子问题要利用到下层的计算结果,换而言之计算上层时,底层的计算结果应该全部计算出来了,不能一边计算上层的值的同时计算下层。以这题为例子,dp[i][j]表示从索引处 i 到 j 的字符串是不是回文,那么最子问题是 i=j 即一个字符的情形,然后根据这个再去计算 2 个字符的情形,全部计算完毕之后再去计算3个字符的情形,以此类推。上面的代码的计算是从i=0开始以此计算dp[0][1],dp[0][2],dp[0,3],dp[0,4].....,而此时以求出的只有字符为1个和2个时所有情形,其它是不知道的,如果在计算dp[0][4]时走到 dp[i][j]=dp[i+1][j-1] 这步的话就必须要计算 dp[1][3],然而此时的dp[1][3]由于没有计算过所以是数组的初始值,根本不是子问题i=1,j=3时的最优解,所以会导致整个dp的计算结果不对。

然后还有一个坑是上面代码最后取字串时直接用了max_long,忘记加上开始索引了,还把substring方法的参数意义记错了,两个参数分别时开始索引和结束索引,不是开始索引和偏移量。最后是正确的dp代码:

class Solution {
public String longestPalindrome(String s) {
int max_long=-1;
int start_index=-1;
if(s.length()<=1) return s;
boolean[][] dp=new boolean[s.length()][s.length()];
for(int i=0;i<s.length()-1;i++){
dp[i][i]=true;
dp[i][i+1]=s.charAt(i)==s.charAt(i+1);
} for(int interval=2;interval<s.length();interval++){
for(int i=0;i<s.length()-interval;i++){
if(s.charAt(i)==s.charAt(i+interval)){
dp[i][i+interval]=dp[i+1][i+interval-1];
}else{
dp[i][i+interval]=false;
}
}
} for(int i=0;i<dp.length;i++){
for(int j=i;j<dp.length;j++){
if(dp[i][j]==true&&(j-i+1>max_long)){
max_long=j-i+1;
start_index=i;
}
}
} return s.substring(start_index, start_index+max_long);
}
}

2. ZigZag Conversion

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

P   A   H   N
A P L S I I G
Y I R

And then read line by line: "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:

string convert(string text, int nRows);

convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR".

解题思路:这题乍看一下有点不明白它说的是什么意思,实际上就是给定n行,原字符串先按竖直一个一个字符放置,到行低之后再斜对角线往上放置,到顶之后再按竖直放置,这样形成一个左旋90度的 “Z” 形摆列。以这样的形式放置完所有字符后在从左往右一行行的读字符,输出摆列后的字符顺序。

一个可行的解题方法是利用 n(这里的n是行数)个StringBuffer作为n行,从原字符数组一个个取字符分别放入各个StringBuffer,到n为止再倒着往从第n个到第一个Stringbuffer里放置字符,到第一个Stringbuffer时再重复此步骤即可。注意这里不需要再考虑斜对角线上字符的位置的,因为最后输出的字符串是按行从左到右输出的,所以只需要知道原字符串排列后每行中有哪些字符即可,根本不需要细纠结排列后每个字符的具体索引。

import java.util.*;

public class LeetCode {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
int n = sc.nextInt(); System.out.println(convert(input, n));
} public static String convert(String s, int nRows) {
char[] c = s.toCharArray();
int len = c.length;
StringBuffer[] sb = new StringBuffer[nRows];
for (int i = 0; i < sb.length; i++) sb[i] = new StringBuffer(); int i = 0;
while (i < len) {
// need to judge whether i<len
for (int idx = 0; idx < nRows && i < len; idx++) // vertically down
sb[idx].append(c[i++]);
for (int idx = nRows-2; idx >= 1 && i < len; idx--) // obliquely up
sb[idx].append(c[i++]);
}
for (int idx = 1; idx < sb.length; idx++)
sb[0].append(sb[idx]);
return sb[0].toString();
}
}

3. 2 Keys Keyboard

Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each step:

  1. Copy All: You can copy all the characters present on the notepad (partial copy is not allowed).
  2. Paste: You can paste the characters which are copied last time.

Given a number n. You have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted. Output the minimum number of steps to get n 'A'.

Example 1:

Input: 3
Output: 3
Explanation:
Intitally, we have one character 'A'.
In step 1, we use Copy All operation.
In step 2, we use Paste operation to get 'AA'.
In step 3, we use Paste operation to get 'AAA'.

这题的意思就是一开始记事本上只有1个A,要得到n个A的话至少需要几个步骤,每一步要么copy all,就是复制所有,不允许部分复制。要么paste,即将上一次复制的内容黏贴。

解题思路:思路一是利用质因数分解,因为A的增长一定是倍数增长,所以如 n 是质数的话,那么再一开始的copy all后只能一个一个paste,要不然不可能达到n。如果n不是质数,对其进行质因数分解,每个质因数即是要paste的次数,从一个质因数到另一个质因数要copyAll一次。一开始有个A,但是一开始要CopyAll以此,所以求所有质因数之和便可以了。

import java.util.*;

public class LeetCode {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(); System.out.println(n);
} public static int solution(int n){
//质因数分解,从2开始判断
int d=2,ans=0;
while(n>1){
while(n%d==0){
ans+=d;
n/=d;
}
d++;
}
return ans;
} }

关于上面的代码中的质因数分解,因为是从2开始判断的,所以一开始找到的肯定是最小质因数,比如对于16,你可能会觉难道不会找到4这种不是质数但是因数的情况么?但实际上因为是从2开始递增判断,所以一开始找到的是2不是4,然后16除以2剩8,8取余2为0,那么得质因数2*2,继续8除2得4。这样下来质因数分解得到的结果是2*2*2*2。

方法二是利用动态规划dp,对于dp来说,首先还是构造数组 dp[i]。数组的值dp[i]是最优解,索引i是要得到几个A,也就是对应于给定的n。动态规划的本质还是有点类似与遍历计算,只不过它能够利用计算好的子问题的值,而不需要重复计算,从而大大缩减了计算量。

对于dp,先是初始化数组。然后采用自低向上或者自顶向下的思路来更新数组。首先用一个例子来说明,对于n为16的情况,最优解应该是对n为8时的最优解CopyAll一次再Paste;n是9时的最优解是对n为3时的最优解CopyAll一次再paste两次。如果n是质数,不能分解成几个数相乘的时候,最优解就是n。

import java.util.*;

public class LeetCode {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(); System.out.println(n);
} public static int solution(int n){
int[] dp=new int[n+1]; for(int i=2;i<=n;i++){
// dp 要素之一,初始化整个dp数组
dp[i]=i; // 更新 dp 数组
for(int j=i-1;j>1;j--){
if(i%j==0){
dp[i]=dp[j]+i/j;
break;
}
}
}
return dp[n];
} }

LeetCode解题报告—— 2 Keys Keyboard & Longest Palindromic Substring & ZigZag Conversion的更多相关文章

  1. 【LeetCode算法题库】Day2:Median of Two Sorted Arrays & Longest Palindromic Substring & ZigZag Conversion

    [Q4] There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of th ...

  2. LeetCode第[5]题(Java):Longest Palindromic Substring 标签:String、动态规划

    题目中文:求最长回文子串 题目难度:Medium 题目内容: Given a string s, find the longest palindromic substring in s. You ma ...

  3. LeetCode.5-最长回文子串(Longest Palindromic Substring)

    这是悦乐书的第342次更新,第366篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Medium级别的第3题(顺位题号是5).给定一个字符串s,找到s中最长的回文子字符串. 您可以假设s ...

  4. 【LeetCode】Longest Palindromic Substring 解题报告

    DP.KMP什么的都太高大上了.自己想了个朴素的遍历方法. [题目] Given a string S, find the longest palindromic substring in S. Yo ...

  5. Leetcode:【DP】Longest Palindromic Substring 解题报告

    Longest Palindromic Substring -- HARD 级别 Question SolutionGiven a string S, find the longest palindr ...

  6. leetcode解题—Longest Palindromic Substring

    题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...

  7. LeetCode 解题报告索引

    最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中......                        ...

  8. LeetCode解题报告汇总! All in One!

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 把自己刷过的所有题目做一个整理,并且用简洁的语言概括了一下思路,汇总成了一个表格. 题目 ...

  9. 【JAVA、C++】LeetCode 005 Longest Palindromic Substring

    Given a string S, find the longest palindromic substring in S. You may assume that the maximum lengt ...

随机推荐

  1. 51nod 1197 字符串的数量 V2(矩阵快速幂+数论?)

    接上一篇,那个递推式显然可以用矩阵快速幂优化...自己随便YY了下就出来了,学了一下怎么用LaTeX画公式,LaTeX真是个好东西!嘿嘿嘿 如上图.(刚画错了一发...已更新 然后就可以过V2了 or ...

  2. Connections between cities LCA

    Problem Description After World War X, a lot of cities have been seriously damaged, and we need to r ...

  3. mapper的前后缀

    1.<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=&quo ...

  4. POJ 3281 最大流

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 17251   Accepted: 7643 Descripti ...

  5. notify()与notifyAll()

    notify() :随机唤醒一个线程. notifyAll():唤醒等待某个锁的所有任务. 在技术上,可能会有多个任务在所创建的任务上处于wait()状态,调用notifyAll()比只调用notif ...

  6. mpvue开发小记

    1.组件嵌套组件时,子组件作用域bug 组件A内的slot包含子组件B的话,无法正常使用变量(这种情况下,B组件的template错误地使用了A的作用域). 我的解决方案:减少一层组件提炼,即这种情况 ...

  7. String StrigBuffer StringBuilder 浅解

    1.String是最基本的字符串类,用于表示字符串. 特点:对象内容不可变,但可以通过指向不同的对象来“表示”不同的内容. 使用场景:如果不涉及到内容改变,可以使用String. 注意:如果想将Str ...

  8. ZooKeeper配额指南(十)

    配额 ZK有命名空间和字节配额.你可以使用ZooKeeperMain类来设置配额.ZK打印警告信息如果用户超过分配给他们的配额.这些信息被打印到ZK的日志中. $java -cp zookeeper. ...

  9. vijos 1180 选课 树形DP

    描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得 ...

  10. bzoj 2434 fail tree+dfs序

    首先比较明显的是我们可以将字符串组建立ac自动机,那么对于询问s1字符串在s2字符串中出现的次数,就是在以s1结尾为根的fail tree中,子树有多少个节点是s2的节点,这样我们处理fail tre ...