分享一个项目中遇到的一个算法题

需求背景:

需求是用户要创建一个任务计划在未来执行,要求在创建任务计划的时候判断选择的时间是否符合要求,否则不允许创建,创建的任务类型有两种,一种是单次,任务只执行一次;另一种是周期,从周一到周日,任务可以重复执行。如果选择单次执行,在选择时间的时候要判断选择的时间是否大于当前时间,如果小于当前时间那么当前任务将不在当天执行而是第二天的同一时间执行,反之是在当天执行。确定好哪一天执行之后还要判断那一天是否有已经创建的任务,如果有再判断同一天的两个时间点是否相差15分钟,如果在15分钟以内则时间发生碰撞不允许创建。如果选择周期执行,也要和已经创建的单次任务或者周期任务进行时间检查,另外两个任务如果不在同一天执行,还要判断在跨天时间点上是否相差15分钟,比如周一晚上23:55和周二凌晨00:05相差10分钟,也是属于时间冲突,那么基于这个需求写一下时间冲突的逻辑判断。

最终调用函数获取结果代码:

复制代码
 val checkResult = mViewModel.checkTime(
            DateUtil.convertTimeToMinutes(startTimeStr),
            StringUtil.convertStringToList(cycleDay),
            vehReservationStandListBean,
            mPreBean?.keyId,
        )

        if (!checkResult.first) {
            "任务时间冲突,任务名称: ${checkResult.second}, 请重新选择时间点".showToast()
            return false
        }

具体检查时间冲突逻辑:

(入参格式:newStartTime="11:30" --> 11*60+30,代表字符串格式hh:mm转成分钟数

newCycleDay = 0,1,2,3,4,5,6,7的list集合,list代表一个已经创建的任务数据体集合)

复制代码
    /**
     * 时间和周期是否允许创建 
     */
    fun checkTime(
        newStartTime: Int?,
        newCycleDay: List<Int>?,
        list: List<ReservationStandSetOperationBean>?,
    ): Pair<Boolean, String?> {
        if (newStartTime == null || newCycleDay == null) {
            return Pair(false, "")
        }

        // 获取新任务的时间段
        val newTimeSlots = DateUtil.getTimeSlots(newCycleDay, newStartTime)


        for (model in list ?: emptyList()) {

            val existingStartTime = DateUtil.convertTimeToMinutes(model.carReadyTime)
            val existingCycleDay = StringUtil.convertStringToList(model.cycleDay)

            if (existingStartTime == null || existingCycleDay == null) {
                continue
            }

            // 获取已存在任务的时间段
            val existingTimeSlots = DateUtil.getTimeSlots(existingCycleDay, existingStartTime)

            // 检查时间段是否重叠
            for (newSlot in newTimeSlots) {
                for (existingSlot in existingTimeSlots) {
                    if (DateUtil.isTimeOverlap(newSlot, existingSlot)) {
                        return Pair(false, model.planName)
                    }
                }
            }
        }
        return Pair(true, "")
    }

返回需要执行时间碰撞的数据集合:

复制代码
        // 获取任务的执行日期和时间段
        fun getTimeSlots(days: List<Int>, startTime: Int): List<Triple<Int, Int, Int>> {
            val result = mutableListOf<Triple<Int, Int, Int>>()
            val minutesInDay = 24 * 60
            val calendar = Calendar.getInstance()
            val now = Date()
            val currentTime =
                calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)
            val weekday = calendar.get(Calendar.DAY_OF_WEEK)
            val today = if (weekday == Calendar.SUNDAY) 7 else weekday - 1

            for (day in days) {
                //任务执行的日期
                var adjustedDay = day

                // 如果是单次任务 需要判断是否需要加一天
                if (days == listOf(0)) {
                    // 如果任务的开始时间小于当前时间,推迟到明天
                    if (startTime <= currentTime) {
                        adjustedDay = if (today == 7) 1 else today + 1
                    } else {
                        adjustedDay = today
                    }
                }

                val endTime = startTime + 15

                // 如果任务跨天
                if (endTime >= minutesInDay) {
                    // 当天的时间段  日期,起始时间,终止时间
                    result.add(Triple(adjustedDay, startTime, minutesInDay))
                    // 第二天的时间段 日期,起始时间,终止时间
                    result.add(
                        Triple(
                            if (adjustedDay == 7) 1 else adjustedDay + 1,
                            0,
                            endTime - minutesInDay
                        )
                    )
                } else {
                    // 不跨天的时间段  日期,起始时间,终止时间
                    result.add(Triple(adjustedDay, startTime, endTime))
                }
            }
            return result
        }

判断两个数据集合是否时间段有重叠:

复制代码
  // 检查时间段是否重叠
        fun isTimeOverlap(slot1: Triple<Int, Int, Int>, slot2: Triple<Int, Int, Int>): Boolean {
            // 如果日期不同,则不重叠
            if (slot1.first != slot2.first) {
                return false
            }

            // 检查时间段是否重叠
            return slot1.second < slot2.third && slot2.second < slot1.third
        }

结语:实际项目中用到的算法逻辑大多不复杂,这种需要动态计算任务执行时间,还要考虑跨天的逻辑比较少见,这里做个记录方便以后有类似逻辑可以做个代码参考。

相关推荐
Kapaseker43 分钟前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭11 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab12 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe17 小时前
Now in Android 架构模式全面分析
android·android jetpack
会员源码网18 小时前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
木心月转码ing19 小时前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
HelloReader19 小时前
Wi-Fi CSI 感知技术用无线信号“看见“室内的人
算法
颜酱1 天前
二叉树分解问题思路解题模式
javascript·后端·算法
qianpeng8971 天前
水声匹配场定位原理及实验
算法