05移除重复节点 06最长回文子串(动态规划)

1.删除重复节点

编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例1:

 输入:[1, 2, 3, 3, 2, 1]
 输出:[1, 2, 3]

示例2:

 输入:[1, 1, 1, 1, 2]
 输出:[1, 2]

提示:
链表长度在[0, 20000]范围内。
链表元素在[0, 20000]范围内。
IPO过程
I :输入一个链表
P:移除重复节点,保留最开始的节点
思路:采用双指针的做法,里层循环为将头指针固定,后续指针在移动,移动过程中如果出现与头指针的值相同的节点,删除该结点,否则继续移动指针。外层循环是头指针在移动
O:输出一个没有重复结点的链表

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var removeDuplicateNodes = function(head) {
//p为头指针
    let p=head
    while(p){
    //q为内层循环移动的指针,这里不采用从p的next开始,是为了后续考虑
        let q=p
        while(q.next){
        if(q.next.val==p.val){           
            q.next=q.next.next           
        }else{
            q=q.next
            }
        }
        //外层移动
         p=p.next;        
    }
    return head
}

2.最长回文子串
题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:

输入: “cbbd”
输出: “bb”

思路
这是一道最长回文的题目,要我们求出给定字符串的最大回文子串。

解决这类问题的核心思想就是两个字“延伸”,具体来说

如果一个字符串是回文串,那么在它左右分别加上一个相同的字符,那么它一定还是一个回文串
如果在一个不是回文字符串的字符串两端添加任何字符,或者在回文串左右分别加不同的字符,得到的一定不是回文串
事实上,上面的分析已经建立了大问题和小问题之间的关联,基于此,我们可以建立动态规划模型。

我们可以用 dp[i][j] 表示 s 中从 i 到 j(包括 i 和 j)是否可以形成回文,状态转移方程只是将上面的描述转化为代码即可:

if (s[i] === s[j] && dp[i + 1][j - 1]) {
  dp[i][j] = true;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
base case就是一个字符(轴对称点是本身),或者两个字符(轴对称点是介于两者之间的虚拟点)。

关键点
”延伸“(extend)
在这里插入图片描述
从中我们可以看出当只有一个字符的时候,dp[i][j]=true;当有两个字符的时候,dp[i][j]=true的情况只有是当两个字符相同的情况;当有三个以上,那么dp[i[j]为true的情况是中间的s[i] === s[j] &&dp[i + 1][j - 1]
以上的IPO过程是:
I:输入一个待验证的字符串
P:判断最大的回文字符串(只需要找出一个)
(1)由于dp[i][j]的结果是依赖于dp[i+1][j-1],因此我们从后往前找,用i表示开始位置,j表示结束位置
(2)从i = s.length - 1开始,循环一次之后i- -;j从i开始,j++

  分为以下三种情况
 1. 当只有一个字符的时候,`dp[i][j]=true`;
 2. 当有两个字符的时候,`dp[i][j]=true`的情况只有是当**两个字符相同**的情况;
 3. 当有三个以上,那么dp[i[j]为true的情况是中间的`s[i] === s[j] &&dp[i + 1][j - 1]`

定义一个res,当dp[i][j] && j - i + 1 > res.length的时候,说明有新的更长的字符串出现,这个时候我们只需要更新res即可
O:输出最大的回文字符串

/**
 * @param {string} s
 * @return {string}
 */

var longestPalindrome = function(s) {
  // babad
  // tag : dp
  if (!s || s.length === 0) return "";
  let res = s[0];

  const dp = [];

  // 倒着遍历简化操作, 这么做的原因是dp[i][..]依赖于dp[i + 1][..]
  for (let i = s.length - 1; i >= 0; i--) {
    dp[i] = [];
    for (let j = i; j < s.length; j++) {
      if (j - i === 0) dp[i][j] = true;
      // specail case 1
      else if (j - i === 1 && s[i] === s[j]) dp[i][j] = true;
      // specail case 2
      else if (s[i] === s[j] && dp[i + 1][j - 1]) {
        // state transition
        dp[i][j] = true;
      }

      if (dp[i][j] && j - i + 1 > res.length) {
        // update res
        res = s.slice(i, j + 1);
      }
    }
  }

  return res;
};

图解来源作者:fe-lucifer
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/hui-wen-wen-ti-dong-tai-gui-hua-jspython5-zui-chan/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值