云服务通用表格识别图片转换

云服务通用表格识别图片转换

1.     题目

今天学习1105专业级第二题。题目:

 

题目描述

华为云推出了“通用表格识别”服务,可以将图片表格转换成文本数据。请你把文本数据进一步转换为「文本型表格」,

如下图所示:https://oj.rnd.huawei.com/public/upload/9ee6c841ae.jpg

 

 

现给出一个图片表格的文本数据:

·         每行数据形如 line3 col1 A,表示第3行第1列的单元格的内容为 A

·         表格的行和列都从 1 开始;文本数据中行、列的最大值分别为表格的行、列数。

·         内容为由英文字符A-Z组成的字符串,或为空;未描述的单元格内容为空。

请按如下格式要求,将文本数据转换成「文本型表格」:

·         表格第一行和最后一行用字母+和字母-组成,+代表单元格的间隔,-代表一个字符的占位符;

·         数据行:

·         用字符|标识单元格的左右边界。

·         某一列的宽度是该列中所有单元格最长内容长度 + 2(即左右各补充 1个空格),该列中内容不足该宽度的用空格补充。

·         表格中单元格的内容要求居中对齐,对齐要求:
1)尽量使得文本左右两侧的空格数量相等。
2)如果文本左右两侧的空格数量无法相等,则左侧比右侧少一个,如图中内容为 CN 的单元格。

输入

第一行一个整数 num,表示文本数据的行数,范围 [1,20]。
接下来 num 行字符串,每行格式如line2 col3 LMN描述一个单元格:

·         line 是行的固定前缀,行取值范围 [1,100]

·         col 是列的固定前缀,列取值范围 [1,100]

·         内容为仅由英文字符A-Z组成的字符串,或为空,长度范围 [0,10]。

输出

字符串表示的「文本型表格」

样例

输入样例 1

8

line1 col3 CN

line1 col1 A

line1 col4 D

line3 col1 X

line2 col1

line2 col2 BE

line2 col3 LMN

line2 col4

输出样例 1

+---+----+-----+---+

| A |    | CN  | D |

|   | BE | LMN |   |

| X |    |     |   |

+---+----+-----+---+

提示样例 1

表格的行列数:
1)输入数据最大行为3,因此行数为 3 。
2)输入数据最大列为4,因此列数为 4 。

表格的各列宽度:

·         第1列:内容最长为1,加2,该列宽度为3 。

·         第2列:内容最长为2,加2,该列宽度为4 。

·         第3列:内容最长为3,加2,该列宽度为5 。该列中内容LMN最长,左右各补充一个空格;CN左侧补充一个空格,右侧补充两个空格。

·         第4列:内容最长为1,加2,该列宽度为3 。



输入样例 2

2

line2 col2 A

line2 col3

输出样例 2

+--+---+--+

|  |   |  |

|  | A |  |

+--+---+--+

提示样例 2

·         从输入得到数据的行列数分别为2和3;第一行、第一列、第三列即使内容为空,也需要输出。

其中第一列内容都为空,列宽度为2(该列中所有单元格最长内容长度 +2)。                                                                                                             

 

2.     题目分析

题目理解:

题目给出一个表格的文字描述作为输入,要求按照指定格式打印输出表格。

需要完成的处理有:

l  解析每一行字符串,得到每个单元格的文本内容

l  因为输入没有直接给出最大行数和列数,所以需要解析得到最大的行数、列数

l  得到每一列的最大宽度

注意点:

l  某一列的宽度是该列中所有单元格最长内容长度 + 2,当整列的单元格都是空的时候,最长内容长度是2

l  单元格内要求居中对齐,如左右两个空格无法相等,则靠左、右边多一个空格

l  输入未描述的单元格文本为空

解题思路:

可以分为两大步骤:

l  构造数据:解析输入字符串,得到所有单元格的文本,同时记录每一列的最大宽度

由于行和列的最大取值是100、每个单元格内的字符串长度最多10,所以可以直接用数组来存储表格内容和每列列宽。

如果数据规模很大(例如超过100万),就要考虑用hash来存储了。

在记录列宽时,直接用len(单元格文本)+2,不用再加上边框字符所占的宽度。

l  显示数据:逐行打印输出每个单元格

打印输出时通常有两种做法:

l  做法1:先填充到数组中,再print整个数组

l  做法2:直接print每一行

 

居中对齐时,用下面这个计算方法是比较简便的:

        int leftFill = (colLen[i] - stringLen) / 2;  // 左边要填充的空格数

        int rightFill = colLen[i] - stringLen - leftFill; // 右边要填充的空格数

以样例1的第1行第3列为例:“| CN  |”,leftFill=(5-2)/2=1,rightFill=5-2-1=2

 

/*

 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.

 * Description: 上机编程认证

 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除

 * 只能import Go标准库

 */

package main

import (
    "bufio"

    "fmt"

    "io"

    "os"

    "strconv"

    "strings"
)

// 待实现函数,在此函数中填入答题代码

type element struct {
    line int

    col int

    content string
}

const (
    minInputNum = 2

    lineIndex = 0

    colIndex = 1

    contentIndex = 2

    twoSpace = 2

    maxInputCol = 100

    maxContentLen = 10
)

func splitString(input string) *element {

    var element element

    str := strings.Split(input, " ")

    if len(str) < minInputNum {

        return nil

    }

    lineStr := strings.TrimLeft(str[lineIndex], "line")

    line, err := strconv.Atoi(strings.TrimSpace(lineStr))

    if err != nil || line < 1 || line > maxInputCol {

        return nil

    }

    colStr := strings.TrimLeft(str[colIndex], "col")

    col, err := strconv.Atoi(strings.TrimSpace(colStr))

    if err != nil || col < 1 || col > maxInputCol {

        return nil

    }

    element.line = line

    element.col = col

    if len(str) > minInputNum {

        element.content = strings.TrimSpace(str[contentIndex])

    }

    if len(element.content) > maxContentLen {

        return nil

    }

    return &element

}

func initLineString(contentLenArr []int, maxCol int) string {

    str := "|"

    i := 0

    for i < maxCol {

        j := 0

        for j < contentLenArr[i]+twoSpace {

            str += " "

            j++

        }

        str += "|"

        i++

    }

    return str

}

func initResultString(contentLenArr []int, maxLine int, maxCol int) []string {

    result := make([]string, 0, maxLine+twoSpace)

    firstLine := "+"

    i := 0

    for i < maxCol {

        j := 0

        for j < contentLenArr[i]+twoSpace {

            firstLine += "-"

            j++

        }

        firstLine += "+"

        i++

    }

    result = append(result, firstLine)

    i = 0

    for i < maxLine {

        str := initLineString(contentLenArr, maxCol)

        result = append(result, str)

        i++

    }

    result = append(result, firstLine)

    return result

}

func createLineString(element *element, lineStr string, contentLenArr []int) string {

    contentNum := len(element.content)

    if contentNum == 0 {

        return lineStr

    }

    startChar := 0

    i := 0

    for i < element.col-1 {

        startChar = startChar + (contentLenArr[i] + twoSpace + 1)

        i++

    }

    startChar = startChar + twoSpace + (contentLenArr[element.col-1]-contentNum)/twoSpace

    result := []byte(lineStr)

    j := 0

    for j < len(element.content) {

        result[startChar] = element.content[j]

        startChar++

        j++

    }

    return string(result)

}

func createResultString(elements []*element, contentLenArr []int, maxLine int, maxCol int) []string {

    result := initResultString(contentLenArr, maxLine, maxCol)

    num := len(elements)

    i := 0

    for i < num {

        lineString := createLineString(elements[i], result[elements[i].line], contentLenArr)

        result[elements[i].line] = lineString

        i++

    }

    return result

}

func transformationTable(tableInfo []string) []string {

    num := len(tableInfo)

    maxLine := 0

    maxCol := 0

    elementArray := make([]*element, 0, num)

    contentLenArr := make([]int, maxInputCol)

    i := 0

    for i < num {

        element := splitString(tableInfo[i])

        if element == nil {

            return nil

        }

        if element.line > maxLine {

            maxLine = element.line

        }

        if element.col > maxCol {

            maxCol = element.col

        }

        if len(element.content) > contentLenArr[element.col-1] {

            contentLenArr[element.col-1] = len(element.content)

        }

        elementArray = append(elementArray, element)

        i++

    }

    return createResultString(elementArray, contentLenArr, maxLine, maxCol)

}

func main() {

    reader := bufio.NewReader(os.Stdin)

    var line int

    if _, err := fmt.Fscanf(reader, "%d\n", &line); err != nil {

        return

    }

    tableInfo, err := readInputStrArrayFromNlines(reader, line)

    if err != nil {

        return

    }

    result := transformationTable(tableInfo)

    for _, value := range result {

        fmt.Println(value)

    }

}

func readInputStrArrayFromNlines(reader *bufio.Reader, num int) ([]string, error) {

    if num <= 0 {

        return []string{}, nil

    }

    result := make([]string, 0, num)

    for i := 0; i < num; i++ {

        lineBuf, err := reader.ReadString('\n')

        if err != nil && err != io.EOF {

            return nil, err

        }

        lineBuf = strings.TrimRight(lineBuf, "\r\n")

        lineBuf = strings.TrimSpace(lineBuf)

        result = append(result, lineBuf)

    }

    return result, nil

}
View Code

 

题目二: 日志记录,树,递归

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2022. All rights reserved.
 * Description: 上机编程认证
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除
 * 只能import Go标准库
 *

2
12:00|test1|1|Create 2
13:00|test2|2|Create 9
1

 */
package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strconv"
    "strings"
)

func ConvertIntSlice2Map(rootIds []int) map[int]struct{} {
    set := make(map[int]struct{}, len(rootIds))
    for _, rootId := range rootIds {
        set[rootId] = struct{}{}
    }
    return set
}

func DeleteStrSlice(messages []string, elem string) []string {
    tmp := make([]string, 0, len(messages))
    for _, message := range messages {
        if message != elem {
            tmp = append(tmp, message)
        }
    }
    return tmp
}

func DeleteIntSlice(rootIds []int, elem int) []int {
    tmp := make([]int, 0, len(rootIds))
    for _, rootId := range rootIds {
        if rootId != elem {
            tmp = append(tmp, rootId)
        }
    }
    return tmp
}

var treeList [][]int

func getDepthTreeList(processIds []int, messages []string) [][]int {
    rootIds := make([]int, 0)
    if len(processIds) == 0 {
        return [][]int{}
    }
    var messageList string
    for messageKey := range messages {
        messageList += messages[messageKey]
    }
    for _, processId := range processIds {
        processIdStr := strconv.Itoa(processId)
        if !strings.Contains(messageList, processIdStr) {
            rootIds = append(rootIds, processId)
        }
    }
    treeList = append(treeList, rootIds)
    mapStructIdList := ConvertIntSlice2Map(processIds)
    // 去掉已经获取到的root节点
    for _, rootId := range rootIds {
        if _, ok := mapStructIdList[rootId]; ok {
            processIds = DeleteIntSlice(processIds, rootId)
        }
    }
    for _, processId := range processIds {
        processIdStr := strconv.Itoa(processId)
        for i := 0; i < len(messages); i++ {
            if strings.Contains(messages[i], processIdStr) {
                messages = DeleteStrSlice(messages, messages[i])
            }
        }
    }
    getDepthTreeList(processIds, messages)
    return treeList
}

func getLastDepth(depth int) int {
    res := 0
    for i := 0; i < len(treeList); i++ {
        if i == (depth - 1) {
            res = len(treeList[i])
        }
    }
    return res
}

// 待实现函数,在此函数中填入答题代码
func logOutput(logs []string, depth int) int {
    // 先构造树
    messages := make([]string, 0)
    processIds := make([]int, 0)
    for _, log := range logs {
        logLists := strings.Split(log, "|")
        processId, err := strconv.Atoi(logLists[2])
        if err != nil {
            return 0
        }
        processIds = append(processIds, processId)
        messages = append(messages, logLists[3])
    }
    treeList = getDepthTreeList(processIds, messages)
    // 统计深度为depth的总数
    ans := getLastDepth(depth)
    return ans
}

func main() {
    reader := bufio.NewReader(os.Stdin)
    logs := readInputStrArrayFromNlines(reader)
    depth := readInputInt(reader)
    result := logOutput(logs, depth)
    fmt.Println(result)
}

func readInputStrArrayFromNlines(reader *bufio.Reader) []string {
    var line int
    if _, err := fmt.Fscanf(reader, "%d\n", &line); err != nil {
        fmt.Println(err.Error())
        return nil
    }
    result := make([]string, 0, line)
    for i := 0; i < line; i++ {
        lineBuf, err := reader.ReadString('\n')
        if err != nil && err != io.EOF {
            fmt.Println(err.Error())
            return nil
        }
        lineBuf = strings.TrimRight(lineBuf, "\r\n")
        lineBuf = strings.TrimSpace(lineBuf)
        result = append(result, lineBuf)
    }
    return result
}

func readInputInt(reader *bufio.Reader) int {
    var num int
    if _, err := fmt.Fscanf(reader, "%d\n", &num); err != nil {
        fmt.Println(err.Error())
        return 0
    }
    return num
}
View Code

 

posted @ 2023-03-11 15:53  易先讯  阅读(86)  评论(0编辑  收藏  举报