2016.5.11_经典试题-回文算法【ABAP】

回文:在一串字符中找到对称出现的字符。

例:7 19 56 99 99 56 24 7 29 1 中回文为:56 99

题目要求输入字符串,找出回文。

思路:

将字符串split进一个内表1,loop表1时创建内表2,两个表对比找一样的字符内容。

内容一致时表1向下一位寻找,表2向上一位寻找,在同一个字符串中找两个位置。

找到则继续,找不到则跳出。

DATA GT_DATA TYPE STANDARD TABLE OF STRING WITH HEADER LINE.
DATA GT_COPY TYPE STANDARD TABLE OF STRING WITH HEADER LINE.
DATA GS_DATA LIKE LINE OF GT_DATA .
DATA GV_ANSWER TYPE STRING.
DATA GV_COUNT TYPE I.

PARAMETER:P_INPUT TYPE STRING DEFAULT '7 19 56 99 99 56 24 7 29 1'.

START-OF-SELECTION.
SPLIT P_INPUT AT SPACE INTO TABLE GT_DATA.

DATA LV_LINES TYPE I.
DATA LV_REST TYPE I.
DATA LV_COUNT TYPE I.
DATA LV_UP LIKE SY-TABIX. 
DATA LV_DN LIKE SY-TABIX.
DATA LV_ANSWER TYPE STRING.
DATA LV_DATA TYPE STRING.

LV_LINES = LINES( GT_DATA ).
LOOP AT GT_DATA.
  LV_UP = SY-TABIX.
  LV_REST = LV_LINES - LV_UP.
 
  GT_COPY[] = GT_DATA[].
  DELETE GT_COPY FROM 1 TO LV_UP.
  LOOP AT GT_COPY WHERE TABLE_line EQ GT_DATA.
    LV_DN = SY-TABIX + LV_UP.

    DO LV_REST TIMES.
      IF LV_DN LE LV_UP.
        CLEAR:LV_COUNT,LV_ANSWER.
        EXIT.
      ENDIF.

      READ TABLE GT_DATA INDEX LV_UP.
      READ TABLE GT_DATA INTO GS_DATA INDEX LV_DN. 
      IF GT_DATA EQ GS_DATA.
        LV_COUNT = LV_COUNT + 1.
        LV_DATA = GS_DATA.
        CONCATENATE LV_ANSWER LV_DATA INTO LV_ANSWER SEPARATED BY SPACE.
        IF LV_COUNT GT GV_COUNT.
          GV_COUNT = LV_COUNT.
          GV_ANSWER = LV_ANSWER.
        ENDIF.
        LV_UP = LV_UP + 1.
        LV_DN = LV_DN - 1. 
      ELSE.
        LV_DN = LV_DN - 1.
        CLEAR:LV_COUNT,LV_ANSWER.
        EXIT.
      ENDIF.  
    ENDDO.
  ENDLOOP. 
ENDLOOP.

WRITE: / GV_COUNT, / GV_ANSWER.

 

这个题算法目前有点难以理解。希望半年后再来看这个题能够完全看懂。2016年11月11号再做一遍这道题。

 

 

 

----------------------20160622更新-------------------------------------------------

 

又遇见一道类似的题,要求找出字符串中最长回文。领导讲解了另一个类型的解法,

因为上面的输入之间有空格,可以方便的split到表里,这道题的输入是一个整体的字符串,

中间没有空格,所以领导用的是角标/位置的方法挨个找,处理对象是整个字符串(上面那种对象是内表)。

处理逻辑用到了递归,感觉略复杂,看代码看了两天还是觉得看不太明白....

 

整理思路如下:

假设字符串gv_string长度为20,那么第一位的角标为0,最后一位的角标为20-1=19.

这样的话第一位值为gv_string+0(1);最后一位为gv_string+19(1).

在循环do里每次从前加角标数,嵌套do里从后减角标数,就实现了在整个字符串里进行前后挨个对比。

但是寻找回文的过程有很多条件会使回文不成立,例如:

前位角标pos1大于后位角标pos2(不成立

假设前位角标为5,说明前四位已经都和字符串剩下的部分对比找过回文了,这时候后位角标应该从19往前找,

找到5就要跳出里面的循环do了,再往前找4位是没有意义的。所以应该满足pos1 lt pos2.

回文长度大于整个字符串的一半(不成立):

整个字符串长度为20,一半为10,当查找回文的单个字符个数大于等于10时,说明回文长度(在目前的嵌套do里)已经是最大了。

计数是计算查找回文找到的次数(这段代码都写在下面那个form里,递归调用),就是计算递归这个form连续用了多少次,

能走到计数的那一步说明能找到回文。长度最大就退出;长度还不够大就让前位向后、后位向前继续寻找相同回文。

 

在外面的嵌套do上,也有很多限制条件:

外面的do是从前往后挨个过滤字符,里面的do是从后往前挨个过滤字符。

在里面的do循环时pos1是不变的,类似这样:

字符串:ABCDEFG

A->G , A->F , A->E , A->D , A->C , A->B (pos1就是A的角标)

然后外面的do第二次:

B->G , B->F , B->E , B->D , B->C

...

 因为题目说明A还有AA这种小于三位的不算回文,所以在嵌套do前做了限制,

让外面的do的次数等于字符串长度-2:

(字符串ABCDEFG,当外面的do找到F这个字符时,里面的do从后往前只会找最后一位G)

字符串外面do找回文找到倒数第2位,那么就算找到了就是AA这种形式,可以排除这种情况,

-2这种设置为了减少循环次数;从前往后找避免了这种情况,同理在里面的do也做了这种排除:

(这里不太理解)

 

全部代码:

DATA GT_SPLIT TYPE TABLE OF STRING .
DATA: GV_CNT    TYPE I,
      GV_ANSWER TYPE STRING.

DATA GS_IN TYPE STRING.

PARAMETERS P_INPUT TYPE STRING DEFAULT '34 AVFSIOAAOIDAGEPLARFEGRTHTRGEFWXGGH'.

START-OF-SELECTION.
  GS_IN = P_INPUT.
  PERFORM F_GET_LENGTH USING GS_IN CHANGING GV_ANSWER.
  IF GV_ANSWER IS INITIAL.
    GV_ANSWER = 0.
  ENDIF.


  WRITE GV_ANSWER.


*&---------------------------------------------------------------------*
*&      Form  F_GET_LENGTH
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->PV_IN      text
*      -->PV_ANSWER  text
*----------------------------------------------------------------------*
FORM F_GET_LENGTH  USING    PV_IN
                   CHANGING PV_ANSWER.
  DATA : LV_LEN_C(10)   TYPE C,
         LV_DATA(1000)  TYPE C,
         LV_LEN         TYPE I,
         LV_POS1        TYPE I,
         LV_POS2        TYPE I,
         LV_ANSWER      TYPE I,
         LV_TMS1        TYPE I,
         LV_TMS2        TYPE I,
         LV_ASW_LEN     TYPE I.

  SPLIT PV_IN AT SPACE INTO  LV_LEN_C LV_DATA.

  LV_LEN = LV_LEN_C.
  IF LV_LEN < 3.  
    PV_ANSWER = 0.
    EXIT.
  ENDIF.

  LV_TMS1 = LV_LEN - 2.
  LV_TMS2 = LV_LEN.

  DO LV_TMS1 TIMES.
    LV_ASW_LEN  = LV_TMS2.
    LV_POS2     = LV_LEN - 1.
    DO LV_TMS2 TIMES.
      CLEAR GV_CNT.
      PERFORM F_GET_ANW USING LV_POS1
                              LV_POS2
                              LV_DATA
                              LV_ASW_LEN
                     CHANGING LV_ANSWER.

      IF LV_ANSWER > PV_ANSWER.
        PV_ANSWER = LV_ANSWER.
      ENDIF.

      LV_ASW_LEN = LV_ASW_LEN - 1.
      IF LV_ASW_LEN < 3.
        EXIT.
      ENDIF.

      LV_POS2 = LV_POS2 - 1.
    ENDDO.
    LV_TMS2 = LV_TMS2 - 1.
    LV_POS1 = LV_POS1 + 1.
  ENDDO.

ENDFORM.                    "F_GET_LENGTH
*&---------------------------------------------------------------------*
*&      Form  F_GET_ANW
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->PV_POS1     text
*      -->PV_POS2     text
*      -->PV_DATA     text
*      <--PV_ANSWER   text
*----------------------------------------------------------------------*
FORM F_GET_ANW  USING    PV_POS1
                         PV_POS2
                         PV_DATA
                         PV_LEN
                CHANGING PV_ANSWER.

  DATA : LV_VAL1 TYPE C,
         LV_VAL2 TYPE C,
         LV_DIV  TYPE I,
         LV_POS1 TYPE I,
         LV_POS2 TYPE I.

  CLEAR : LV_VAL1, LV_VAL2, PV_ANSWER.

  IF PV_POS1 >= PV_POS2.
    EXIT.
  ENDIF.

  LV_VAL1 = PV_DATA+PV_POS1(1).
  LV_VAL2 = PV_DATA+PV_POS2(1).
  IF LV_VAL1 NE LV_VAL2.
    EXIT.
  ENDIF.

  LV_DIV = PV_LEN DIV 2.

  GV_CNT = GV_CNT + 1.
  IF GV_CNT >= LV_DIV.
    PV_ANSWER = PV_LEN.
    EXIT.
  ELSE.
    LV_POS1 = PV_POS1 + 1.
    LV_POS2 = PV_POS2 - 1.

    PERFORM F_GET_ANW USING LV_POS1
                            LV_POS2
                            PV_DATA
                            PV_LEN
                   CHANGING PV_ANSWER.

  ENDIF.

ENDFORM.                    "F_GET_ANW

 

两种解法只是换了对象,思路是一样的,对一个字符串一边从前往后,一边从后往前去挨个遍历,就是退出循环的条件比较抽象,

还需要多看看,争取能自己写出来。今年要啃下这道题!

posted @ 2016-05-11 12:45  fieldcatalog  阅读(410)  评论(0编辑  收藏  举报