哈希表题目:设计推特

这篇具有很好参考价值的文章主要介绍了哈希表题目:设计推特。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目

标题和出处

标题:设计推特

出处:355. 设计推特

难度

7 级

题目描述

要求

设计一个简化版的推特,可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近 10 \texttt{10} 10 条推文。

实现 Twitter \texttt{Twitter} Twitter 类:

  • Twitter() \texttt{Twitter()} Twitter() 初始化简易版推特对象。
  • void   postTweet(int   userId,   int   tweetId) \texttt{void postTweet(int userId, int tweetId)} void postTweet(int userId, int tweetId) 根据给定的 tweetId \texttt{tweetId} tweetId userId \texttt{userId} userId 创建一条新推文。每次调用此函数都会使用一个不同的 tweetId \texttt{tweetId} tweetId
  • List<Integer>   getNewsFeed(int   userId) \texttt{List<Integer> getNewsFeed(int userId)} List<Integer> getNewsFeed(int userId) 检索当前用户新闻推送中最近 10 \texttt{10} 10 条推文的 ID 。新闻推送中的每一项都必须是由用户关注的人或者是用户自己发布的推文。推文必须按照时间顺序由最近到最远排序
  • void   follow(int   followerId,   int   followeeId) \texttt{void follow(int followerId, int followeeId)} void follow(int followerId, int followeeId) ID 为 followerId \texttt{followerId} followerId 的用户开始关注 ID 为 followeeId \texttt{followeeId} followeeId 的用户。
  • void   unfollow(int   followerId,   int   followeeId) \texttt{void unfollow(int followerId, int followeeId)} void unfollow(int followerId, int followeeId) ID 为 followerId \texttt{followerId} followerId 的用户不再关注 ID 为 followeeId \texttt{followeeId} followeeId 的用户。

示例

示例 1:

输入:
["Twitter",   "postTweet",   "getNewsFeed",   "follow",   "postTweet",   "getNewsFeed",   "unfollow",   "getNewsFeed"] \texttt{["Twitter", "postTweet", "getNewsFeed", "follow", "postTweet", "getNewsFeed", "unfollow", "getNewsFeed"]} ["Twitter", "postTweet", "getNewsFeed", "follow", "postTweet", "getNewsFeed", "unfollow", "getNewsFeed"]
[[],   [1,   5],   [1],   [1,   2],   [2,   6],   [1],   [1,   2],   [1]] \texttt{[[], [1, 5], [1], [1, 2], [2, 6], [1], [1, 2], [1]]} [[], [1, 5], [1], [1, 2], [2, 6], [1], [1, 2], [1]]
输出:
[null,   null,   [5],   null,   null,   [6,   5],   null,   [5]] \texttt{[null, null, [5], null, null, [6, 5], null, [5]]} [null, null, [5], null, null, [6, 5], null, [5]]
解释:
Twitter   twitter   =   new   Twitter(); \texttt{Twitter twitter = new Twitter();} Twitter twitter = new Twitter();
twitter.postTweet(1,   5); \texttt{twitter.postTweet(1, 5);} twitter.postTweet(1, 5); // 用户 1 \texttt{1} 1 发送了一条新推文( id   =   5 \texttt{id = 5} id = 5)。
twitter.getNewsFeed(1); \texttt{twitter.getNewsFeed(1);} twitter.getNewsFeed(1); // 用户 1 \texttt{1} 1 的获取推文应当返回一个列表,其中包含 1 \texttt{1} 1 条推文 [5] \texttt{[5]} [5]
twitter.follow(1,   2); \texttt{twitter.follow(1, 2);} twitter.follow(1, 2); // 用户 1 \texttt{1} 1 关注了用户 2 \texttt{2} 2
twitter.postTweet(2,   6); \texttt{twitter.postTweet(2, 6);} twitter.postTweet(2, 6); // 用户 2 \texttt{2} 2 发送了一条新推文( id   =   6 \texttt{id = 6} id = 6)。
twitter.getNewsFeed(1); \texttt{twitter.getNewsFeed(1);} twitter.getNewsFeed(1); // 用户 1 \texttt{1} 1 的获取推文应当返回一个列表,其中包含 2 \texttt{2} 2 条推文 [6,   5] \texttt{[6, 5]} [6, 5]。推文 id   =   6 \texttt{id = 6} id = 6 应当在推文 id   =   5 \texttt{id = 5} id = 5 之前,因为它是在推文 id   =   5 \texttt{id = 5} id = 5 之后发送的。
twitter.unfollow(1,   2); \texttt{twitter.unfollow(1, 2);} twitter.unfollow(1, 2); // 用户 1 \texttt{1} 1 取消关注了用户 2 \texttt{2} 2
twitter.getNewsFeed(1); \texttt{twitter.getNewsFeed(1);} twitter.getNewsFeed(1); // 用户 1 \texttt{1} 1 获取推文应当返回一个列表,其中包含 1 \texttt{1} 1 条推文 [5] \texttt{[5]} [5],因为用户 1 \texttt{1} 1 已经不再关注用户 2 \texttt{2} 2

数据范围

  • 1 ≤ userId,   followerId,   followeeId ≤ 500 \texttt{1} \le \texttt{userId, followerId, followeeId} \le \texttt{500} 1userId, followerId, followeeId500
  • 0 ≤ tweetId ≤ 10 4 \texttt{0} \le \texttt{tweetId} \le \texttt{10}^\texttt{4} 0tweetId104
  • 所有推特的 ID 都互不相同
  • postTweet \texttt{postTweet} postTweet getNewsFeed \texttt{getNewsFeed} getNewsFeed follow \texttt{follow} follow unfollow \texttt{unfollow} unfollow 方法最多调用 3 × 10 4 \texttt{3} \times \texttt{10}^\texttt{4} 3×104

前言

这道题要求设计一个简化版的推特,需要支持以下功能:

  1. 创建新推文;
  2. 检索最近 10 10 10 条推文,并按照时间顺序由最近到最远排序;
  3. 关注用户;
  4. 取消关注用户。

功能 3 和功能 4 的实现较为简单,只需要维护一个关注用户的哈希表,对每个用户使用一个哈希集合存储该用户关注的用户集合。如果 ID 为 followerId \textit{followerId} followerId 的用户关注 ID 为 followeeId \textit{followeeId} followeeId 的用户,则在 followerId \textit{followerId} followerId 对应的哈希集合中加入 followeeId \textit{followeeId} followeeId;如果取消关注,则在对应的哈希集合中将被关注者移除。

功能 1 和功能 2 的实现较为复杂。功能 1 需要对每个用户维护一个按时间倒序排序的推文列表,功能 2 需要得到当前用户和该用户关注的所有用户的推文列表并检索这些推文中的最近 10 10 10 条推文。为了实现检索推文功能,可以对每个用户维护一个链表,链表中的每个结点存储一条推文的信息,结点按照时间倒序排序,检索推文时可以使用「合并K个升序链表」的做法,得到最近 10 10 10 条推文。

存储推文信息的链表可以使用单向链表或者双向链表。

解法一

思路和算法

使用单向链表存储推文信息,则每个用户对应的链表的头结点为该用户最新创建的推文(如果用户没有创建过推文则链表为空)。链表中的每个结点需要包含以下信息:推文 ID、创建时间和上一条推文的结点。

推特类中需要维护以下信息:

  • 推文时间,记录当前时间,每次发布推文时更新推文时间然后创建新推文;
  • 用户推文哈希表,记录每个用户对应的推文列表;
  • 关注用户哈希表,记录每个用户关注的用户集合。

构造方法中,将推文时间初始化为 0 0 0,将两个哈希表初始化。

对于 postTweet \textit{postTweet} postTweet 操作,将推文时间加 1 1 1,在用户推文哈希表中得到 userId \textit{userId} userId 对应的推文列表,根据 tweetId \textit{tweetId} tweetId 和推文时间创建新推文对应的结点,添加到推文列表的头部。

对于 getNewsFeed \textit{getNewsFeed} getNewsFeed 操作,得到 userId \textit{userId} userId 及其关注的全部用户的推文列表,使用优先队列存储每个用户的非空推文列表,优先队列存储结点,队首结点为创建时间最大的推文对应的结点。每次从优先队列中取出剩余结点中的创建时间最大的结点,将该结点对应的推文 ID 添加到结果中,然后判断该结点的上一条推文的结点是否为空,如果不为空则加入优先队列。重复该操作直到结果中有 10 10 10 个推文 ID,或者优先队列变为空,然后返回结果。

对于 follow \textit{follow} follow 操作,在关注用户哈希表中得到 followerId \textit{followerId} followerId 对应的哈希集合,将 followeeId \textit{followeeId} followeeId 加入到该哈希集合中。

对于 unfollow \textit{unfollow} unfollow 操作,在关注用户哈希表中得到 followerId \textit{followerId} followerId 对应的哈希集合,将 followeeId \textit{followeeId} followeeId 从该哈希集合中移除。

代码

class Twitter {
    private class Node {
        private int tweetId;
        private int time;
        private Node prev;

        public Node(int tweetId, int time, Node prev) {
            this.tweetId = tweetId;
            this.time = time;
            this.prev = prev;
        }

        public int getTweetId() {
            return tweetId;
        }

        public int getTime() {
            return time;
        }

        public Node getPrev() {
            return prev;
        }
    }

    private static final int MAX_RECENT = 10;
    private int time = 0;
    private Map<Integer, Node> userTweetsMap;
    private Map<Integer, Set<Integer>> followeeMap;

    public Twitter() {
        time = 0;
        userTweetsMap = new HashMap<Integer, Node>();
        followeeMap = new HashMap<Integer, Set<Integer>>();
    }

    public void postTweet(int userId, int tweetId) {
        time++;
        Node prev = userTweetsMap.get(userId);
        Node curr = new Node(tweetId, time, prev);
        userTweetsMap.put(userId, curr);
    }

    public List<Integer> getNewsFeed(int userId) {
        List<Integer> mostRecent = new ArrayList<Integer>();
        PriorityQueue<Node> pq = new PriorityQueue<Node>((a, b) -> b.getTime() - a.getTime());
        if (userTweetsMap.containsKey(userId)) {
            pq.offer(userTweetsMap.get(userId));
        }
        Set<Integer> followees = followeeMap.getOrDefault(userId, new HashSet<Integer>());
        for (int followee : followees) {
            Node node = userTweetsMap.get(followee);
            if (node != null) {
                pq.offer(node);
            }
        }
        for (int i = 0; i < MAX_RECENT && !pq.isEmpty(); i++) {
            Node node = pq.poll();
            mostRecent.add(node.getTweetId());
            Node prev = node.getPrev();
            if (prev != null) {
                pq.offer(prev);
            }
        }
        return mostRecent;
    }

    public void follow(int followerId, int followeeId) {
        followeeMap.putIfAbsent(followerId, new HashSet<Integer>());
        followeeMap.get(followerId).add(followeeId);
    }

    public void unfollow(int followerId, int followeeId) {
        followeeMap.putIfAbsent(followerId, new HashSet<Integer>());
        followeeMap.get(followerId).remove(followeeId);
    }
}

复杂度分析

  • 时间复杂度:构造方法的时间复杂度是 O ( 1 ) O(1) O(1),创建推文、关注用户和取消关注用户操作的时间复杂度都是 O ( 1 ) O(1) O(1),检索推文操作的时间复杂度是 O ( u log ⁡ u ) O(u \log u) O(ulogu),其中 u u u 是用户数量。
    创建推文操作需要从哈希表中得到用户对应的推文列表,然后在链表头部添加结点,时间复杂度是 O ( 1 ) O(1) O(1)
    关注用户和取消关注用户操作需要从哈希表中得到用户对应的哈希集合,然后在哈希集合中添加或移除元素,时间复杂度是 O ( 1 ) O(1) O(1)
    检索推文操作需要将用户和关注的每个用户对应的推文列表,需要在优先队列中执行 u u u 次添加元素和 10 10 10 次移除元素操作,每次操作的时间复杂度是 O ( log ⁡ u ) O(\log u) O(logu),因此总时间复杂度是 O ( u log ⁡ u ) O(u \log u) O(ulogu)

  • 空间复杂度: O ( u 2 + t ) O(u^2 + t) O(u2+t),其中 u u u 是用户数量, t t t 是推文数量。需要使用两个哈希表记录每个用户的推文列表和每个用户关注的用户集合,用户推文哈希表需要 O ( u + t ) O(u + t) O(u+t) 的空间,关注用户哈希表需要 O ( u 2 ) O(u^2) O(u2) 的空间(最坏情况下,每个用户都关注全部用户),因此空间复杂度是 O ( u + t + u 2 ) = O ( u 2 + t ) O(u + t + u^2) = O(u^2 + t) O(u+t+u2)=O(u2+t)

解法二

思路和算法

解法一需要在每个用户的推文列表中存储该用户创建的全部推文。由于每次检索推文只需要返回当前用户及其关注的全部用户创建的所有推文中的最近 10 10 10 条推文,因此不需要存储全部推文,对于每个用户,最多只需要存储最近的 10 10 10 条推文,从而优化空间。为了实现空间优化,如果一个用户的推文列表的长度大于 10 10 10,则需要将该用户最早创建的推文从推文列表中删除,直到推文列表的长度减少到 10 10 10

由于单向链表无法快速定位到尾结点,因此需要使用双向链表存储每个推文信息。和单向链表的结点相比,双向链表的结点需要多记录一项信息:下一条推文的结点。

为了便于操作,双向链表需要维护伪头结点、伪尾结点和链表的长度,链表的实际头结点为伪头结点的上一条推文的结点,链表的实际尾结点为伪尾结点的下一条推文的结点(只有当链表不为空时才存在实际头结点和实际尾结点)。初始时,伪头结点和伪尾结点相邻。链表的长度为链表的结点数,不包括伪头结点和伪尾结点,初始时链表的长度为 0 0 0

对于 postTweet \textit{postTweet} postTweet 操作,在双向列表的伪头结点的上一条推文处添加新推文对应的结点,如果添加结点之后链表的长度大于 10 10 10,则将双向链表的伪尾结点的下一条推文处的结点删除,确保每个用户的推文列表的长度不超过 10 10 10。实现方法可以参考「设计链表」的双向链表解法。

对于 getNewsFeed \textit{getNewsFeed} getNewsFeed 操作,其做法和解法一相同,但是由于使用双向链表,因此具体实现有所不同。

其余操作和解法一相同。

代码

class Twitter {
    private class DoublyLinkedList {
        private Node pseudoHead;
        private Node pseudoTail;
        private int size;

        public DoublyLinkedList() {
            pseudoHead = new Node();
            pseudoTail = new Node();
            pseudoHead.setPrev(pseudoTail);
            pseudoTail.setNext(pseudoHead);
            size = 0;
        }

        public void addNode(Node node) {
            Node prevNode = pseudoHead.getPrev();
            node.setPrev(prevNode);
            prevNode.setNext(node);
            pseudoHead.setPrev(node);
            node.setNext(pseudoHead);
            size++;
            if (size > MAX_RECENT) {
                Node removeNode = pseudoTail.getNext();
                pseudoTail.setNext(removeNode.getNext());
                removeNode.getNext().setPrev(pseudoTail);
                size--;
            }
        }

        public Node getHead() {
            return pseudoHead.getPrev();
        }

        public int getSize() {
            return size;
        }
    }

    private class Node {
        private int tweetId;
        private int time;
        private Node prev;
        private Node next;

        public Node() {
            this(-1, -1);
        }

        public Node(int tweetId, int time) {
            this.tweetId = tweetId;
            this.time = time;
        }

        public int getTweetId() {
            return tweetId;
        }

        public int getTime() {
            return time;
        }

        public Node getPrev() {
            return prev;
        }

        public void setPrev(Node prev) {
            this.prev = prev;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }
    }

    private static final int MAX_RECENT = 10;
    private int time = 0;
    private Map<Integer, DoublyLinkedList> userTweetsMap;
    private Map<Integer, Set<Integer>> followeeMap;

    public Twitter() {
        time = 0;
        userTweetsMap = new HashMap<Integer, DoublyLinkedList>();
        followeeMap = new HashMap<Integer, Set<Integer>>();
    }

    public void postTweet(int userId, int tweetId) {
        time++;
        userTweetsMap.putIfAbsent(userId, new DoublyLinkedList());
        userTweetsMap.get(userId).addNode(new Node(tweetId, time));
    }

    public List<Integer> getNewsFeed(int userId) {
        List<Integer> mostRecent = new ArrayList<Integer>();
        PriorityQueue<Node> pq = new PriorityQueue<Node>((a, b) -> b.getTime() - a.getTime());
        if (userTweetsMap.containsKey(userId)) {
            userTweetsMap.putIfAbsent(userId, new DoublyLinkedList());
            DoublyLinkedList list = userTweetsMap.get(userId);
            if (list.getSize() > 0) {
                Node node = list.getHead();
                pq.offer(node);
            }
        }
        Set<Integer> followees = followeeMap.getOrDefault(userId, new HashSet<Integer>());
        for (int followee : followees) {
            userTweetsMap.putIfAbsent(followee, new DoublyLinkedList());
            DoublyLinkedList list = userTweetsMap.get(followee);
            if (list.getSize() > 0) {
                Node node = list.getHead();
                pq.offer(node);
            }
        }
        for (int i = 0; i < MAX_RECENT && !pq.isEmpty(); i++) {
            Node node = pq.poll();
            mostRecent.add(node.getTweetId());
            Node prev = node.getPrev();
            if (prev.getTweetId() >= 0) {
                pq.offer(prev);
            }
        }
        return mostRecent;
    }

    public void follow(int followerId, int followeeId) {
        followeeMap.putIfAbsent(followerId, new HashSet<Integer>());
        followeeMap.get(followerId).add(followeeId);
    }

    public void unfollow(int followerId, int followeeId) {
        followeeMap.putIfAbsent(followerId, new HashSet<Integer>());
        followeeMap.get(followerId).remove(followeeId);
    }
}

复杂度分析

  • 时间复杂度:构造方法的时间复杂度是 O ( 1 ) O(1) O(1),创建推文、关注用户和取消关注用户操作的时间复杂度都是 O ( 1 ) O(1) O(1),检索推文操作的时间复杂度是 O ( u log ⁡ u ) O(u \log u) O(ulogu),其中 u u u 是用户数量。
    创建推文操作需要从哈希表中得到用户对应的推文列表,然后在链表头部添加结点,时间复杂度是 O ( 1 ) O(1) O(1)
    关注用户和取消关注用户操作需要从哈希表中得到用户对应的哈希集合,然后在哈希集合中添加或移除元素,时间复杂度是 O ( 1 ) O(1) O(1)
    检索推文操作需要将用户和关注的每个用户对应的推文列表,需要在优先队列中执行 u u u 次添加元素和 10 10 10 次移除元素操作,每次操作的时间复杂度是 O ( log ⁡ u ) O(\log u) O(logu),因此总时间复杂度是 O ( u log ⁡ u ) O(u \log u) O(ulogu)

  • 空间复杂度: O ( u 2 + M × u ) O(u^2 + M \times u) O(u2+M×u),其中 u u u 是用户数量, M M M 是检索的最大推文数量, M = 10 M = 10 M=10。需要使用两个哈希表记录每个用户的推文列表和每个用户关注的用户集合,由于每个用户最多需要记录 M M M 条推文,因此用户推文哈希表需要 O ( u + M × u ) O(u + M \times u) O(u+M×u) 的空间,关注用户哈希表需要 O ( u 2 ) O(u^2) O(u2) 的空间(最坏情况下,每个用户都关注全部用户),因此空间复杂度是 O ( u + M × u + u 2 ) = O ( u 2 + M × u ) O(u + M \times u + u^2) = O(u^2 + M \times u) O(u+M×u+u2)=O(u2+M×u)文章来源地址https://www.toymoban.com/news/detail-449510.html

到了这里,关于哈希表题目:设计推特的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 哈希表C++哈希表详解(知识点+相关LeetCode题目)

    目录 前言 一、什么是哈希表 二、哈希表的操作 2.1 操作时间复杂度 2.2 哈希表通用API 2.3 建立哈希表 2.3 哈希表常见结构介绍 Set(集合) Map(映射) unordered_map(哈希表) 三、哈希表的力扣经典题目 有效的字母异位词242 两个数组的交集 349 两数之和1 四数相加II 454 三数之和

    2024年03月20日
    浏览(38)
  • 哈希表题目:TinyURL 的加密与解密

    标题:TinyURL 的加密与解密 出处:535. TinyURL 的加密与解密 7 级 要求 TinyURL 是一种 URL 简化服务。当你输入一个 URL,例如 https://leetcode.com/problems/design-tinyurl 时,它将返回一个简化的 URL,例如 http://tinyurl.com/4e9iAk 。设计一个类对 URL 加密和对 TinyURL 解密。 你的加密和解密算法如

    2024年02月04日
    浏览(24)
  • 全面理解哈希,哈希的底层原理是如何实现的,哈希题型的做题思路与题目清单(不断更新)

    哈希(Hash)是一种算法,它接受一个输入(或“消息”),并返回一个固定大小的字符串。这个输出字符串的大小通常以字节为单位,输出的内容看起来是随机的且整个过程是单向的。 哈希的一些关键特性包括: 不管你输入的信息有多大,哈希值的大小总是固定的。 即使只

    2024年02月04日
    浏览(34)
  • 必刷算法题之哈希篇(题目及代码)---C++

    解法1 :(对于大规模数据,时间和空间复杂度会超出) 解题思路如下: 假设第一个数为a,用目标值c减去第一个数a,得到b,然后遍历后面的数,查看b是否在后面的数组中 解法2 :(利用哈希表) 解法1 :(排序) 由于多数元素是指在数组中出现次数大于 【n/2】 的元素,

    2023年04月18日
    浏览(29)
  • C#从入门到入坟(不易,转载请注明出处)

    安装Visual Studio。 下载地址:https://visualstudio.microsoft.com/zh-hans/ 可以选择社区版本,是可以免费使用的。 下载之后配置安装。 按照自己的工作需要,勾选相应的组件和安装位置,进行安装即可。 目前C#开发的两种框架 运行于windows的.Net Framework 可以跨平台的.Net6 项目名称 建议

    2024年02月05日
    浏览(31)
  • stable-diffusion-webui的基础功能手动安装,了解代码结构、依赖、模型出处

    Stable Diffusion `一键安装包( 解压即用 防爆显存 ):https://www.bilibili.com/video/BV1iM4y1y7oA/ 相关博文: 1.stable-diffusion-webui安装(2):扩展模块extensions——汉化、双语等 2. stable-diffusion 训练GUI安装——lora、dreambooth 虽然,当前 B站 有很多stable-diffusion-webui 的一键安装包,但是不易

    2024年01月19日
    浏览(40)
  • 推特运营的方法

    推特是一个广泛使用的社交媒体平台,可以通过以下方法来运营和营销: 建立一个完整的个人或品牌资料:确保你的推特资料页面清晰、有吸引力,并包含关键信息,如个人简介、网站链接和联系方式。 确定目标受众:明确你想要吸引的目标受众,如年龄、地理位置、兴趣

    2024年02月05日
    浏览(23)
  • 什么是一致性哈希?一致性哈希是如何工作的?如何设计一致性哈希?

    如果你有 n 个缓存服务器,一个常见的负载均衡方式是使用以下的哈希方法: 服务器索引 = 哈希(键) % N ,其中 N 是服务器池的大小。 让我们通过一个例子来说明这是如何工作的。如表5-1所示,我们有4台服务器和8个字符串键及其哈希值。 为了获取存储某个键的服务器,我们

    2024年02月06日
    浏览(43)
  • 推特如何安全注册?如何防封?

    近日跨境圈发生了一个大新闻,社交媒体巨头推特正式更名与标示为“X”,这一举措引发了广泛关注和讨论。 twitter一直以来对于做跨境业务的小伙伴来说是电商运营、广告投放、客户维系的重要阵地。此次改版,也意味着之后更加支持跨境玩家的深耕。还没有开拓这个领域

    2024年02月21日
    浏览(36)
  • 2023 年最新Java 毕业设计选题题目参考,500道 Java 毕业设计题目,值得收藏

    大家好,我是程序员徐师兄,最近有很多同学咨询,说毕业设计了,不知道选怎么题目好,有哪些是想需要注意的。 确实毕设选题实际上对很多同学来说一个大坑 , 每年挖坑给自己跳的人太多太多,选题选得好后面的答辩以及论文撰写会轻松很多,选的不好就是一个无穷无

    2024年02月08日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包