力扣_中级算法_数组_5~6题_和链表_1~2题

一位C++小白的力扣刷题_成长记录_welcome to visit  ^_^  

 

数组_第5题:最长回文子串

题目描述:

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

举例

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

解题思路:采用类似于哈希表的 标记法。在一个二维的 “ vector 容器 ” 里面做标记。 这里其实有一个动态规划的思想。在力扣的 官方解题思路里有,结合了数学公式,很详细。

学习心得:做了这道题后,再一次让我感受到了 “数学思维”的重要性。 看官方解题思路,让我豁然开朗,

虽然,看了答案后,在之后自己独立敲地过程中还是遇到了很多问题。但最后还是解决了,深入分析,真正

弄懂了,小有成就。 嘿,等我第二遍来刷你时,我可不会手下留情的!

实现:(C++)

class Solution {
  public:
    string longestPalindrome(string s) {
    int n=s.size();
    vector<vector<int>> dp( n,vector<int>(n) );      //"()"里的n不能省去呀....
    string res;
    if ( n==1 ) return s;          //特殊情况,特殊处理
    int i,t;
    for( t=0;t<n;t++ )             //字符串s的有效长度为多少,就循环多少次
      for( i=0;i+t<n&&i+1<n;i++ )
      {
       if( t==0 )               //使“vector”二维容器里的对角线 上的数组值为1。即最短字符串
           dp[i][i+t]=1;
       else if( t==1 )         //如果 s[i]==s[i+t] ,注意 ,这里的t=1,即字符串里相邻的两个元素值相同时,对应“vector”二维容器里的元素 值赋为1
        dp[i][i+t] = ( s[i]==s[i+t] );
       else
          {
             dp[i][i+t] = ( s[i]==s[i+t]&&dp[i+1][i+t-1] );     //首尾字符相同,字符串里面的 字符串是回文字符串 。前面两个条件满足,才能给“vector”二维容器里 相应的元素赋值为1
        }
        if( dp[i][i+t]&&t+1>res.size() )          //只有遇到“vector”二维容器里 标记为1的元素,说明才有 回文字符串。 注: t+1 其实是 (i+t)-i+1
            res=s.substr( i,t+1 );

     }
  return res;
  }
};

运行结果: 

代码执行结果:
我的输入
"babad"
我的答案
"bab"
预期答案
"bab"

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

数组_第6题: 递增的三元子序列

题目描述:

给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。

数学表达式如下:

如果存在这样的 i, j, k,  且满足 0 ≤ i < j < k ≤ n-1,
使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否则返回 false 。

说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1) 。

举例:

示例 1:

输入: [1,2,3,4,5]
输出: true

示例 2:

输入: [5,4,3,2,1]
输出: false

解题思路:先找前两者 min 和 mid( middle 的意思),然后找第三者(即 max),这里需要注意的是,当遇到一个数,值在 min 和 mid 之间时,要把这个数值 赋给 mid。当遇到

一个数,值小于 min 时,要把这个值 赋给min 。虽然可能遇到 这种情况 [ 1,2,0,3 ]  ,但你细品品,对于结果的 正确性,也是没问题的呦。

学习心得:做这道题,主要在 min 和 mid 的初始化上,摔了很多坑。 mid不能由 数组中的某个元素赋值。

应当 给他赋 INT_MAX。 具体原因,看看代码,想一想就懂了。这道题不难,刚开始我还满怀信心,以为

我能凭一己之力,轻轻松松地将其解决。可是提交五六次都失败,害。原来呀,许多细节没做好。 渐渐醒悟,

敲代码,是个细针手活呀~

实现:(C++) 

class Solution {
 public:
  bool increasingTriplet(vector<int>& nums) {
  if( nums.size()<=2 ) return false;
  int i,min=nums[0],mid=INT_MAX; // mid 得赋int类型的最大值:INT_MAX。 这样可以保证,只有执行过第一个 “else if” ,才有可能执行 第二个 “else if”,不然,

                                                            //可能还没执行第一个,直接执行第二个“else if”。
  for( i=1;i<nums.size();i++ )
    {
        if( nums[i]<min )
              min=nums[i];
     else if( nums[i]<mid&&nums[i]>min )
         mid=nums[i];
     else if( nums[i]>mid )
         return true;
    }
  return false;
 }
};

运行结果:

代码执行结果:
我的输入
[1,2,3,4,5]
我的答案
true
预期答案
true

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

链表_第1题:两数相加

题目描述:

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

举例:

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

解题思路:我的解题思路是,先使两个链表对位对齐,没有的 用 “0” 来补上(申请动态空间来补)。然后进行逐位相加,并把进制问题认真处理。

学习心得:练习了这道题后,我仿佛看到了一些更深远的东西。 int型、double型 始终只能分别表示32位、64位。

但这链表可长着了! 这让我明白了为什么 π (圆周率)可以写到小数点后 一亿位。 所得斯勒!I got it!做了这

道题,也让我再次熟悉了一下链表操作,以及 申请动态空间的操作。

实现:(C++)

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
  public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode *head=new ListNode(-1);      //哑结点
    ListNode *fp=head;        //用来移动的指针
    ListNode *p=l1;          //l1是指向链表头的头指针,一般不动它,另外建立一个指针来使用
    ListNode *q=l2;
    int flag=0,sum=0;        //flag 用来判断是否进位,其值要么是1,要么是0
    int len_1=0,len_2=0;
    if( l1==NULL ) return l2;
    if( l2==NULL ) return l1;
    while ( p->next!=NULL ) { len_1++; p=p->next; }      //注意,这里有个细节,while() 循环的括号里是“ p->next!=NULL ”,而不是 “ p!=NULL ”。如果不这样,在后面 就不能在 l1的链表末尾

                              //新生成一个结点。因为如果不这样,p就指向了 “空”,生成的结点 并没有和 l1的链表末尾连接起来。
    while ( q->next!=NULL ) { len_2++; q=q->next; }
    if( len_1>len_2 )
        while( len_1>len_2 )
           { q->next=new ListNode (0); q=q->next; len_2++; }
    else if( len_1<len_2)
         while( len_1<len_2 )
             { p->next=new ListNode (0); p=p->next; len_1++; }
    while( l1!=NULL&&l2!=NULL )
    {
       sum+=l1->val+l2->val;       //sum用来记录相加结果
       l1=l1->next;
       l2=l2->next;
       fp->next=new ListNode( (sum+flag)%10 );  //sum要加上 上两位数相加后的 进位标记flag的值
       fp=fp->next;
      if( (sum+flag)>=10 )
          flag=1;
      else
          flag=0;
      sum=0;
    }
    if( flag==1 )      //如果最后,flag值还为1,就再申请一个 结点
        fp->next=new ListNode( 1 );
    return head->next;      //返回 哑结点的下一位结点的地址
      }
};

运行结果:

代码执行结果:
我的输入
[2,4,3]
[5,6,4]
我的答案
[7,0,8]
预期答案
[7,0,8]

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

链表_第2题: 奇偶链表

题目描述

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

举例:

示例 1:

输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL

示例 2:

输入: 2->1->3->5->6->4->7->NULL 
输出: 2->3->6->7->1->5->4->NULL

说明:

  • 应当保持奇数节点和偶数节点的相对顺序。
  • 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

解题思路:我的思路就是,在构造一个链表,两次遍历,分别储存 目标链表的 奇位数的 、偶位数的 结点。

学习心得:原地算法,害,我的小脑瓜想不出来呀。 现在,我能独立完成一道中等难度的题就有点小满足了。

虽然心里还是力求更高,但少年,别慌,咱们慢慢磨刀。第二遍时,优化,优化。

实现:(C++)

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
  public:
    ListNode* oddEvenList(ListNode* head) {
    ListNode* res=new ListNode(-1);     //哑结点
    ListNode* fp=res;
    ListNode* h=head;
    int i=1;
    while( h!=NULL )
      {
         if( i%2==1 )       //先储存奇位数的 结点
      {
        fp->next=new ListNode( h->val);
        fp=fp->next;
        h=h->next;
           }
       else
             h=h->next;
       i++;
       }
    i=1;
    h=head;                 //准备好第二次遍历
    while( h!=NULL)
     {
         if( i%2==0)      //在储存偶位数的 结点
      {
         fp->next=new ListNode( h->val);
         fp=fp->next;
         h=h->next;
        }
      else
         h=h->next;
      i++;
     }
  return res->next;
 }
};

运行结果:

代码执行结果:
我的输入
[1,2,3,4,5]
我的答案
[1,3,5,2,4]
预期答案
[1,3,5,2,4]


原文地址:https://www.cnblogs.com/Wang-dou-dou/p/13311253.html