前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[数据结构与算法] 输入当前是一周的第几天, 输出今天直到三天后分别都是星期几

[数据结构与算法] 输入当前是一周的第几天, 输出今天直到三天后分别都是星期几

作者头像
时间静止不是简史
发布2022-04-02 08:18:01
1.1K0
发布2022-04-02 08:18:01
举报
文章被收录于专栏:Java探索之路Java探索之路

算法之路

本系列随缘更新

第一章 [数据结构与算法] 邂逅数组与队列 第二章 [数据结构与算法] 邂逅链表 第三章 [数据结构与算法] 邂逅栈 第四章 [数据结构与算法] 排序算法 第五章 [数据结构与算法] 排序算法之冒泡排序与快速排序(快排) 第六章 [数据结构与算法] 排序算法之选择排序和堆排序 第七章 [数据结构与算法] 排序算法之直接插入排序与希尔排序 第八章 [数据结构与算法] 排序算法之归并排序与基数排序 第九章 [数据结构与算法] 查找算法 第十章 [数据结构与算法] 树结构之二叉树 第十一章 [数据结构与算法] 树结构之二叉排序树、平衡二叉树、多路查找树 第十二章 [数据结构与算法]赫夫曼树与赫夫曼编码 第十三章 [数据结构与算法] 图结构 第十四章 [数据结构与算法] 盘点工作中常用的算法 第十五章 [数据结构与算法] 输入当前是一周的第几天, 返回今天直到三天后分别都是星期几


输入当前是一周的第几天, 输出今天直到三天后分别都是星期几


一. 前言

对该问题进行抽象, 实际上就是是: 输入当前是星期几, 输出从今到几天后所有的星期数( 都是星期几 ) 这个算法一种情况就是用于前端 在下拉选择时间框的时候, 设置几天内可预约时间 我们可以先将问题具体化: 输入当前是一周的第几天, 返回今天到3天之后分别都是星期几, 最后再进行抽象化 通过对问题的梳理, 来推敲简单算法实现的过程, 并举一反三对问题进行多方位思考


二. 分析

我们可以先将可能的情况写下来, 便于观察规律

代码语言:javascript
复制
//要求: 输入周几, 返回该天至该天后3天都是星期几
周一 1 2 3 4 
周二 2 3 4 5
周三 3 4 5 6
周四 4 5 6 7
周五 5 6 7 1
周六 6 7 1 2
周日 7 1 2 3

注意:

  1. 本例因为可能性较少因此进行了穷举
  2. 如果元素较少, 可以考虑穷举; 如果元素较多, 则按照自己的想法去列举, 直至能发现其中的规律

根据上面规律, 我们很容易发现

  • 当天在周一~周四, 天数介于 当天~当天+3 之间
  • 当天在周五~周日, 天数介于 当天~周末周一 ~ 当天-4 之间
代码语言:javascript
复制
//周一 ~ 周四很好理解
//周五 ~ 周日的情况需要想想办法了
周五 5 6 7 1      
周六 6 7 1 2		 
周日 7 1 2 3		

//首尾对应看下, 可以看到下面对应关系 并不能在数组 或者 list中 通过连续遍历 获得
5-->1
6-->2
7-->3
//因此, 我们需要人为的去构建这种连续, 比如
8-7=1
9-7=2
10-7=3
//而8,9,10 和5,6,7 有什么关系呢?
那就是前者等于后者+3!!! 而这个3 正好对应的是几天后(时间段)

根据上面的猜想, 我们能够较为快速的想到

  • 去构建一个 1 - 10连续的, 并且存放10个元素的数组
  • 然后去按顺序遍历这些数组, 当数组元素大于7时, 减去7 即可( 这里的思路很关键 ) 遍历的 开始是day-1 (作用是将当前星期几与上面数组建立联系, 数组下标从0开始) 遍历的 结束是: day+2. (因为 day-1, day, day+1, day+2 正好是当前天数到3天后的星期数) 判断遍历的结果, 小于7不变, 大于7 则直接 - 7 即可!!!

三. 实现

以上思路代码实现如下

代码语言:javascript
复制
    /**
     * 输入当前星期几, 输出当前到几天后的值
     * @return
     */
    public static List<Integer> getDayOfThreeDayAfter(int day) {
        //初始化数据
        Integer[] week = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        //动态初始化list
        List<Integer> list = new ArrayList<>();
        //四个时间段 d-1, d, d+1. d-2
        for (int i = day-1; i <= day+ 2; i++) {
            //判断遍历的结果, 小于7不变, 大于7 则直接 - 7
            list.add(week[i] > 7 ? week[i] - 7 : week[i]);
        }
        return list;
    }

    public static void main(String[] args) {
        /**
         * 要求: 输入周几, 返回该天至该天后3天都是星期几
         * 周一 1 2 3 4
         * 周二 2 3 4 5
         * 周三 3 4 5 6
         * 周四 4 5 6 7
         * 周五 5 6 7 1
         * 周六 6 7 1 2
         * 周日 7 1 2 3
         */
        for (int i = 1; i <= 7; i++) {
            System.out.println("getDayOfThreeDayAfter("+i+") = " + getDayOfThreeDayAfter(i));
        }

    }

测试结果

在这里插入图片描述
在这里插入图片描述

拓展

将当前方法进行抽象, 使其效果达到: 输入当前星期几, 以及时间间隔, 输出从当前到几天后的星期数(分别都是星期几)

核心注意点:

  • 数组初始后的容量设置和动态赋值
  • 数组遍历的初始值和结束值的设计
代码语言:javascript
复制
   /**
     * 输入当前星期几, 输出当前到几天后的值
     * @param today  今天星期几
     * @param days  几天后
     * @return
     */
    public static List<Integer> getDaysOfThreeDayAfter(int today, int days) {
        //初始化数组
        Integer[] week = new Integer[7+days];
        for (int j = 0; j < 7 + days ; j++) {
            week[j] = j + 1;
        }
        //动态初始化list
        List<Integer> list = new ArrayList<>();
        //四个时间段 d-1, d, d+1. d-2
        for (int i = today - 1; i <= today + days-1; i++) {
            //判断遍历的结果, 小于7不变, 大于7 则直接 - 7
            list.add(week[i] > 7 ? week[i] - 7 : week[i]);
        }
        return list;
    }

    public static void main(String[] args) {
        for (int i = 1; i <= 7; i++) {
            System.out.println("getDaysOfThreeDayAfter(" + i + ") = " + getDaysOfThreeDayAfter(i, 4));
        }

测试结果

在这里插入图片描述
在这里插入图片描述

我们回顾下上面代码的实现思路

1.去构建一个 1 - 10 ,连续的, 存放10个元素的数组 2. 然后去按顺序遍历这些数组, 当数组元素大于7时, 减去7 即可( 这里的思路很关键 ) 遍历的 开始是day-1 (作用是将当前星期几与上面数组简历联系, 数组下标从0开始) 遍历的 结束是: day+2. (因为 day-1, day, day+1, day+2 正好是当前天数到3天后的星期数) 判断遍历的结果, 小于7不变, 大于7 则直接 - 7 即可!!!

灵光一闪

反向思考 既然上面的方式核心是在list 初始化后遍历取值的时候, 值的变化(小于7不变, 大于7 则直接 - 7) 那么我们为什么不可以将核心转移到 数组初始化后动态赋值的时候呢. 这样我们后面仅需要确定遍历的起始下班和结束下标即可

以上思考的思路如下:

  • 构建一个包含1-10连续的, 存放10个元素的数组, 判断每个元素的值是否大于7, 大于7则-7, 小于7则不变
  • 然后去按顺序遍历这些数组, 遍历的 开始是day-1 (作用是将当前星期几与上面数组简历联系, 数组下标从0开始) 遍历的 结束是day+2. (因为 day-1, day, day+1, day+2 正好是当前天数到3天后的星期数)

推广到该天到任意天数之间的星期数

  • 构建一个包含1-7+days (days为时间段) 连续7+days 个元素的数组, 判断每个元素的值是否大于7, 大于7则-7, 小于7则不变
  • 然后去按顺序遍历这些数组, 遍历的 开始是day-1 (作用是将当前星期几与上面数组简历联系, 数组下标从0开始) 因为 days=3, 结束坐标=today+3 -1 ; days=4 ,结束坐标=today+4-1; days=5, 结束坐标=today+5-1 遍历的 结束坐标是: today + days-1.
代码语言:javascript
复制
    /**
     * 拓展方式的另一种变种, 就是在初始化时, 就将数据初始好, 在list动态初始化时直接遍历即可
     * 输入当前星期几, 输出当前到几天后的值
     * @param today  今天星期几
     * @param days  几天后
     * @return
     */
    public static List<Integer> getDaysOfThreeDayAfter2(int today, int days) {
        //初始化数组
        Integer[] week = new Integer[7+days];
        for (int j = 0; j < 7 + days ; j++) {
            //在数组初始化时, 判断j+1的值和7的关系: 小于7不变, 大于7 则直接 - 7
            week[j] = (j + 1) > 7 ? (j + 1) - 7 : j + 1;
        }
        //动态初始化list
        List<Integer> list = new ArrayList<>();
        //四个时间段 d-1, d, d+1. d-2
        for (int i = today - 1; i <= today + days-1; i++) {
            list.add(week[i]);
        }
        return list;
    }

    public static void main(String[] args) {
        for (int i = 1; i <= 7; i++) {
            System.out.println("getDaysOfThreeDayAfter2(" + i + ") = " + getDaysOfThreeDayAfter2(i, 4));
        }

    }
在这里插入图片描述
在这里插入图片描述

补充: 建立星期和日期的映射, 用于在进行遍历时, 根据所属星期几设置当前时间

代码语言:javascript
复制
    /**
     * 输入当前星期几, 返回几天后的星期数与对应日期数
     * 注意: 不能超过7天, 即days不能 >=6
     * @param today
     * @param days
     * @return
     */
    public static Map<Integer, String> getDaysOfThreeDayAfterAndDate(int today, int days) {
        //初始化数组
        Integer[] week = new Integer[7 + days];
        for (int j = 0; j < 7 + days; j++) {
            //在数组初始化时, 判断j+1的值和7的关系: 小于7不变, 大于7 则直接 - 7
            week[j] = (j + 1) > 7 ? (j + 1) - 7 : j + 1;
        }
        //动态初始化list
        List<Integer> list = new ArrayList<>();
        //初始化Map 用户存放当前日期
        Map<Integer, String> dateMap = new LinkedHashMap<>(16);
        //四个时间段 d-1, d, d+1. d-2
        for (int i = today - 1, k = 0; i <= today + days - 1; i++, k++) {
            list.add(week[i]);
            dateMap.put(week[i], LocalDateTime.now().toLocalDate().plusDays(k).toString());
        }
        return dateMap;
    }

总结

  • 个人认为, 相比拓展中 getDaysOfThreeDayAfter对list 初始化后动态赋值并进行判断, 灵光一闪中 getDaysOfThreeDayAfter2 对数组初始化后动态赋值更容易接受一些. 因为这样做将最难的问题, 赋值问题在一开始就解决, 剩下我们只需注意遍历时的坐标即可
  • 从之前学习算法的经验以及自己造轮子(虽然比较简单)的经历可以体会到. 最核心问题是算法设计思路, 其次就是对数据进行赋值(数组初始化容量, 动态赋值)和遍历(起始和结束下标) . 只要这些点能够掌握, 算法就可能没有想象中的那么简单
  • 之前从某位大佬那里学习到. 要从战略上藐视技术, 从战术上重视技术. 究其根本原因就是, 其实技术本来就是由繁入简. 最为难以搞定的机器语言, 汇编语言已经由业界前辈们为我们封装成黑盒代码, 我们直接调用对应api就可以使用了. 并且通过各种语言成熟的框架借以让更多人去轻松掌握技术, 从事技术, 进而推动业务发展, 适应更加复杂的业务情况 但是如果不去多多学习新技术, 去提高我们的开发效率, 我们就只能故步自封. 很可能无法应对今后的工作环境
  • 因此无论多难的问题, 对其进行拆分, 然后对其各个击破, 最后几乎都能将其解决. 这也正契合大数据技术中 分而治之 的思想.
  • 私以为, 之所以都推荐学习底层源码和原理或者算法等原因是: 方便我们更好的理解技术/框架, 解决平时无法通过常规方式来解决的问题

万变不离其宗, 多多反思, 努力学习和体会技术发展的本质!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 算法之路
    • 输入当前是一周的第几天, 输出今天直到三天后分别都是星期几
    • 一. 前言
    • 二. 分析
    • 三. 实现
      • 拓展
        • 灵光一闪
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档