算法-项号箱号缩写并顺序拼接

405 阅读1分钟
   在公司业务开发中遇到一个小小的算法场景,遂记录整理至本文章。

需求:在文件附件备注栏上要把项号和箱号之间的对应关联关系用缩略写法并按顺序拼写的方式写上,一个项号只能对应一箱,一箱能包含多个项号。

这个要求前可能的备注栏写法:"项3,4在第3箱,项5,6,8,9,18,19,1,10,11,16,17,12,13,15,20在第1箱,项7,14,2在第2箱"。(项号,箱号均可能为无序,且连续项号没有缩写)

完成要求后的备注栏写法:"项1,5-6,8-13,15-20在第1箱,项2,7,14在第2箱,项3-4在第3箱"。(项号,箱号均有序,连续项号用"-"缩写)

完成需求的代码如下:

<?php

    /**
     * 将连续项号用“-”号省略并按顺序拼接,追加到箱号前,箱号亦按顺序排列
     * 力扣 128-最长连续序列 300-最长递增子序列 简单版变种
     * @see https://leetcode-cn.com/problems/longest-consecutive-sequence/
     *      https://leetcode-cn.com/problems/longest-increasing-subsequence/
     * @param array $detail_box 箱号与项号映射的数组,其中子数组中,box_num为箱号, g_no为项号
     * @return string 效果如: 项1,5-6,8-13,15-20在第1箱,项2,7,14在第2箱,项3-4在第3箱
     */
    function boxRemark($detail_box)
    {
        $kgnos  = array_column($detail_box,'g_no');
        $kboxes = array_column($detail_box,'box_num');
        // 此处使用了高级数组内置方法,按照力扣标准,需要为纯手写代码
        array_multisort($kgnos, SORT_ASC, $kboxes, SORT_ASC, $detail_box);

        $box_to_gno = [];  // 数组保存box_num和g_no的对应关系
        foreach ($detail_box as $k => $map){
            $box_to_gno[$map['box_num']][$map['g_no']] = 1;
        }

        // 循环下来判断是不是在连续同一个箱子内
        $string = '';
        foreach ($box_to_gno as $box => $value){
            $i = 1; $pev_gno = -1; $gno_str = ''; $end = -1; $start = -1;

            $end_ele = max(array_keys($value));
            foreach ($value as $gno => $value2){
                if($i == 1){
                    $start = $gno;
                }else{ // i >= 2
                    if($gno == $pev_gno + 1){  // 连续
                        $end = $gno;
                    }else{                     // 断开
                        if($end == -1){
                            $gno_str .= $pev_gno.',';
                        }else{
                            $gno_str .= $start.'-'.$end.',';
                        }
                        $start = $gno;
                        $end = -1;
                    }
                }
                $pev_gno = $gno;
                $i++;

                if($gno == $end_ele){
                    if($end == -1){
                        $gno_str .= $pev_gno.',';
                    }else{
                        $gno_str .= $start.'-'.$end.',';
                    }
                }
            }
            if(strpos($gno_str,",") !== false){
                $gno_str = substr($gno_str,0,-1);
            }
            // 解决箱子数目重复的问题
            if(strpos($box,",") !== false){
                $tmp_box = array_unique(explode(",",$box));
                ksort($tmp_box);
                $box = implode(",",$tmp_box);
            }

            $string .= '项'.$gno_str."在第".$box."箱,";
        }

        return mb_substr($string,0,-1,'utf-8');
    }


    // 测试运行结果
    $detail_box = [
        ['g_no' => 12,'box_num'=>1],
        ['g_no' => 5, 'box_num'=>1],
        ['g_no' => 6, 'box_num'=>1],
        ['g_no' => 8, 'box_num'=>1],
        ['g_no' => 9, 'box_num'=>1],
        ['g_no' => 20,'box_num'=>1],
        ['g_no' => 7, 'box_num'=>2],
        ['g_no' => 16,'box_num'=>1],
        ['g_no' => 13,'box_num'=>1],
        ['g_no' => 14,'box_num'=>2],
        ['g_no' => 18,'box_num'=>1],
        ['g_no' => 1, 'box_num'=>1],
        ['g_no' => 2, 'box_num'=>2],
        ['g_no' => 11,'box_num'=>1],
        ['g_no' => 15,'box_num'=>1],
        ['g_no' => 4, 'box_num'=>3],
        ['g_no' => 3, 'box_num'=>3],
        ['g_no' => 10,'box_num'=>1],
        ['g_no' => 19,'box_num'=>1],
        ['g_no' => 17,'box_num'=>1],
    ];
    $string = boxRemark($detail_box);
    echo $string;  // 项1,5-6,8-13,15-20在第1箱,项2,7,14在第2箱,项3-4在第3箱

本文也算作为日常开发中的一点经验的累积了,或者说是随手笔记好了。