LeetCode刷题笔记(Java)---第341-360题

前言

需要开通vip的题目暂时跳过

笔记导航

点击链接可跳转到所有刷题笔记的导航链接

341.扁平化嵌套列表迭代器

给你一个嵌套的整型列表。请你设计一个迭代器,使其能够遍历这个整型列表中的所有整数。

列表中的每一项或者为一个整数,或者是另一个列表。其中列表的元素也可能是整数或是其他列表。

在这里插入图片描述

  • 解答

    public class NestedIterator implements Iterator<Integer> {
    
        private Stack<Integer> s1 = new Stack<>();
        private Stack<Integer> s2 = new Stack<>();
    
        public NestedIterator(List<NestedInteger> nestedList) {
            dfs(nestedList);
            while(!s1.empty()) {
                s2.push(s1.pop());
            }
        }
    
        @Override
        public Integer next() {
            return s2.pop();
        }
    
        @Override
        public boolean hasNext() {
            return !s2.isEmpty();
        }
    
        private void dfs(List<NestedInteger> nestedList) {
            for (NestedInteger temp : nestedList) {
                if (temp.isInteger()) {
                    s1.push(temp.getInteger());
                } else {
                    dfs(temp.getList());
                }
            }
        }
    }
    
  • 分析

    1. 深度搜索遍历给定的嵌套链表
    2. 遇到数字则直接压栈,否则递归
    3. 然后将栈中的元素出栈进另一个栈中。
    4. 之后调用next()方法只需要直接返回栈顶即可
    5. hasNext()就判断栈是否为空。
  • 提交结果
    在这里插入图片描述

342.4的幂

给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。

在这里插入图片描述

进阶:
你能不使用循环或者递归来完成本题吗?

  • 解答

    		//方法一
    		public static boolean isPowerOfFour(int num) {
            String s = Integer.toString(num, 4);
            if (s.charAt(0) != '1') return false;
            for (int i = 1; i < s.length(); i++) {
                if (s.charAt(i) != '0') {
                    return false;
                }
            }
            return true;
        }
    		//方法二
    		public boolean isPowerOfFour(int num) {
        		return (num > 0) && ((num & (num - 1)) == 0) && ((num & 0xaaaaaaaa) == 0);
      	}
    		//方法三
    		public static boolean isPowerOfFour(int num) {
            return (num > 0) && (Math.log(num) / Math.log(2) % 2 == 0);
        }
    
  • 分析

    1. 方法一,一开始的想到的就是将num转换成4进制。这样如果是4的幂次,那么只有第一位是1,其余位为0。

    2. 方法二,在方法1的基础上,他的2进制也是满足首位为1,其余位为0。并且可以发现4的幂次和二进制(101010…10)做与运算等于0。num & 0xaaaaaaaa) == 0光这个判断还不够,因为例如5也符合条件。所以需要加上(num & (num - 1)) == 0,这个条件成立,表示仅有最高位为1.

    3. 方法三,根据数学公式推导 ,得到a是个整数即可。

    在这里插入图片描述

  • 提交结果

    方法一在这里插入图片描述

    方法二在这里插入图片描述

    方法三在这里插入图片描述

343. 整数拆分

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

在这里插入图片描述

  • 解答

    		// 方法一
    		int[] maxMut = new int[59];
        public int integerBreak(int n) {
            calMax();
            return maxMut[n];
        }
        public void calMax(){
            maxMut[1] = 1;
            maxMut[2] = 1;
            for(int i = 3;i<=58;i++){
                for(int j = 1;j<=i/2;j++){
                    int remain = i-j;
                    maxMut[i] = Math.max(maxMut[i],Math.max(Math.max(j * remain,maxMut[j] * remain),j * maxMut[remain]));
                }
            }
        }
    		//方法二
    		public int integerBreak(int n) {
            int[] dp = new int[n+1];
            dp[1] = 1;
            dp[2] = 1;
            for (int i = 3;i <= n;i++){
                for(int j = 1;j <= i - j;j++){
                    dp[i] = Math.max(dp[i],j*(i-j));
                    dp[i] = Math.max(dp[i],j*dp[i-j]);
                }
            }
            return dp[n];
        }
    		//方法三
    		int[] maxMut = new int[59];
        public int integerBreak(int n) {
            calMax();
            return maxMut[n];
        }
        public void calMax() {
            maxMut[1] = 1;
            maxMut[2] = 1;
            for (int i = 3; i <= 58; i++) {
                maxMut[i] = Math.max(Math.max(2 * (i - 2), 2 * maxMut[i - 2]), Math.max(3 * (i - 3), 3 * maxMut[i - 3]));
            }
        }
    
  • 分析

    1. 方法一记忆集搜索

    2. 将每个数字可以得到的最大乘机缓存下来。

    3. 遍历3~58,每个数字进行拆分成j和remain,得到的结果最大值有2种情况

      1. j * remain 拆分后的乘积为最大
      2. j * matMut[remain] 剩余部分继续拆分后的乘积更大
    4. 方法二

    5. 参考方法一写成dp的形式。

    6. 方法三

    7. 在第一个方法上的改进,每次数字拆分仅要考虑拆成2和i-2 或3和i-3即可。

  • 提交结果

    方法一在这里插入图片描述

    方法二在这里插入图片描述

    方法三在这里插入图片描述

344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

在这里插入图片描述

  • 解答

    		// 方法一
    		public void reverseString(char[] s) {
            reverseString(s,0,s.length-1);
        }
    
        public void reverseString(char[] s,int left,int right){
            if(right <= left)return;
            char temp = s[left];
            s[left++] = s[right];
            s[right--] = temp;
            reverseString(s,left,right); 
        }
    		//方法二
    		public void reverseString(char[] s) {
            int len = s.length;
            for(int i = 0;i < len/2;i++){
                char temp = s[i];
                s[i] = s[len-1-i];
                s[len-1-i] = temp;
            }
        }
    
  • 分析

    1. 方法一 递归版首尾交换,但是会用到栈空间
    2. 方法二 首尾指针。
  • 提交结果

    方法一在这里插入图片描述

    方法二在这里插入图片描述

345.反转字符串中的元音字母

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

在这里插入图片描述

  • 解答

    public String reverseVowels(String s) {
            int len = s.length();
            if (len <= 1) return s;
            char[] chars = new char[]{'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'};
            HashSet<Character> hash = new HashSet<>();
            for (int i = 0; i < chars.length; i++) {
                hash.add(chars[i]);
            }
            int l = 0, r = len - 1;
            char[] arr = s.toCharArray();
            while (l <= r) {
                boolean jL = hash.contains(arr[l]);
                boolean jR = hash.contains(arr[r]);
                if (jL && jR) {
                    char temp = arr[l];
                    arr[l++] = arr[r];
                    arr[r--] = temp;
                } else if (jL && !jR) {
                    r--;
                } else if (!jL && jR) {
                    l++;
                } else {
                    r--;
                    l++;
                }
            }
            return new String(arr);
        }
    
  • 分析

    1. 双指针,头尾遍历,寻找到元音字母交换。
  • 提交结果在这里插入图片描述

347.前 K 个高频元素

给定一个非空的整数数组,返回其中出现频率前 *k* 高的元素。

在这里插入图片描述

提示:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
你可以按任意顺序返回答案。

  • 解答

    		public int[] topKFrequent(int[] nums, int k) {
            HashMap<Integer, Integer> map = new HashMap<>();
            PriorityQueue<Pair<Integer, Integer>> priorityQueue = new PriorityQueue<>(new Comparator<Pair>() {
                @Override
                public int compare(Pair o1, Pair o2) {
                    return (int) o2.getValue() - (int) o1.getValue();
                }
            });
            for (int i = 0; i < nums.length; i++) {
                map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
            }
            for (Integer integer : map.keySet()) {
                priorityQueue.add(new Pair(integer, map.get(integer)));
            }
            int[] result = new int[k];
            for (int i = 0; i < k; i++) {
                result[i] = priorityQueue.poll().getKey();
            }
            return result;
       }
    
  • 分析

    1. 第一个map用于记录数字和对应出现的次数。
    2. 优先级队列,当作大顶堆,这样从堆顶取出的元素就是里面最大的。这个堆根据map中数字的次数大小来构建。
    3. 第一个循环,遍历nums数组,统计数字出现的次数。
    4. 第二个循环,遍历map,将数字和对应的次数组成Pair对象,添加到优先级队列。
    5. 第三个循环,从优先级队列中取堆顶元素,取k次。即可得到答案。
  • 提交结果在这里插入图片描述

349.两个数组的交集

给定两个数组,编写一个函数来计算它们的交集。

在这里插入图片描述

  • 解答

    		public int[] intersection(int[] nums1, int[] nums2) {
            HashSet<Integer> set = new HashSet<>();
            HashSet<Integer> used = new HashSet<>();
            for(int i = 0;i<nums1.length;i++){
                set.add(nums1[i]);
            }
            ArrayList<Integer> list = new ArrayList<>();
            for(int i = 0;i<nums2.length;i++){
                if(set.contains(nums2[i]) && !used.contains(nums2[i])){
                    list.add(nums2[i]);
                    used.add(nums2[i]);
                }
            }
            int[] res = new int[list.size()];
            for(int i = 0;i< res.length;i++){
                res[i] = list.get(i);
            }
            return res;
        }
    
  • 分析

    1. 第一个set,用来存nums1中出现的数字。
    2. used用来存已经在答案中的数字,避免重复添加。
    3. list用来存答案。最后根据这个list的大小构建一个数字,然后将list里的数据放到数组中返回。
    4. 第一个for循环,将nums1中的数字加入到set集合中。
    5. 第二个for循环,遍历nums2,判断是否在set中出现并且还没有出现在答案中。若满足条件,则加入到list和used中。
    6. 第三个for循环,将list中的答案放到数组中
  • 提交结果在这里插入图片描述

350. 两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。

在这里插入图片描述

说明:

  • 输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
  • 我们可以不考虑输出结果的顺序。
  • 解答

    	//方法一
    	public int[] intersect(int[] nums1, int[] nums2) {
            HashMap<Integer,Integer> map1 = new HashMap<>();
            HashMap<Integer,Integer> map2 = new HashMap<>();
            for(int num:nums1){
                map1.put(num,map1.getOrDefault(num,0)+1);
            }
            for(int num:nums2){
                map2.put(num,map2.getOrDefault(num,0)+1);
            }
            ArrayList<Integer> list = new ArrayList<>();
            for(Integer i :map2.keySet()){
                if(map1.containsKey(i)){
                    int number = Math.min(map1.get(i),map2.get(i));
                    for(int j = 0;j<number;j++){
                        list.add(i);
                    }
                }
            }
            int[] res = new int[list.size()];
            for(int i = 0;i<res.length;i++){
                res[i] = list.get(i);
            }
            return res;
        }
    	// 方法二
    	public int[] intersect(int[] nums1, int[] nums2) {
            if (nums1.length > nums2.length) {
                return intersect(nums2, nums1);
            }
            Map<Integer, Integer> map = new HashMap<Integer, Integer>();
            for (int num : nums1) {
                int count = map.getOrDefault(num, 0) + 1;
                map.put(num, count);
            }
            int[] res = new int[nums1.length];
            int index = 0;
            for (int num : nums2) {
                int count = map.getOrDefault(num, 0);
                if (count > 0) {
                    res[index++] = num;
                    count--;
                    if (count > 0) {
                        map.put(num, count);
                    } else {
                        map.remove(num);
                    }
                }
            }
            return Arrays.copyOfRange(res, 0, index);
        }
    	//方法三
    	public int[] intersect(int[] nums1, int[] nums2) {
            Arrays.sort(nums1);
            Arrays.sort(nums2);
            int length1 = nums1.length, length2 = nums2.length;
            int[] res = new int[Math.min(length1, length2)];
            int index1 = 0, index2 = 0, index = 0;
            while (index1 < length1 && index2 < length2) {
                if (nums1[index1] < nums2[index2]) {
                    index1++;
                } else if (nums1[index1] > nums2[index2]) {
                    index2++;
                } else {
                    res[index] = nums1[index1];
                    index1++;
                    index2++;
                    index++;
                }
            }
            return Arrays.copyOfRange(res, 0, index);
        }
    
  • 分析

    1. 方法一
    2. map1和map2分别统计两个数组中数字出现的次数
    3. 前两个for循环就是做这件事情
    4. 然后遍历map2中的键值对。判断是否在map1中有出现一样的数字。
    5. 若出现了,则判断两个map中记录该数字出现的次数,选择小的那个,添加多次该数字到答案中
    6. 然后根据list构建一个数字,将list中的答案放入数组中,返回。
    7. 方法二
    8. 对方法一进行了改进,不需要先统计出两个数组中数字出现的次数,只需要先统计长度短的数组中数字出现的次数。
    9. 然后遍历长度长的那个数组
    10. 判断是否在map中出现了。若出现了,则添加到答案中,并使map中该数字对应的次数-1。若结果为0了,则将该数字从map中移除。因为决定答案结果是出现次数少的一个数组里该数字的次数。
    11. 方法三
    12. 先将两个数组排序。
    13. 使用双指针来同时遍历两个数组。
    14. 若两个指针指向的数字相同,则添加到答案中。然后两个指针后移
    15. 若不相同,则将指向数字小的一个指针后移。
    16. 当一个指针超过了数组的界限则停下。
  • 提交结果

    方法一在这里插入图片描述

    方法二在这里插入图片描述

    方法三在这里插入图片描述

352. 将数据流变为多个不相交区间

给定一个非负整数的数据流输入 a1,a2,…,an,…,将到目前为止看到的数字总结为不相交的区间列表。

例如,假设数据流中的整数为 1,3,7,2,6,…,每次的总结为:

在这里插入图片描述

进阶:
如果有很多合并,并且与数据流的大小相比,不相交区间的数量很小,该怎么办?

提示:
特别感谢 @yunhong 提供了本问题和其测试用例。

  • 解答

    class SummaryRanges {
    
         private List<int[]> list = new ArrayList<>();
    
        /** Initialize your data structure here. */
        public SummaryRanges() {
        }
    
        public void addNum(int val) {
            if (list.size() == 0) {//第一次插入
                int[] arr = {val,val};
                list.add(arr);
                return;
            }
    
            int insertPosition = findInsertPosition(val);//二分查找,若val存在某一区间 返回-1
            if (insertPosition == list.size()) {//若插入的位置是在最后
                if (val == list.get(list.size() - 1)[1] + 1) {//若当前的最后一个区间的右边的值+1 刚好等于val,则将当前区间的右侧值修改为val。
                    list.get(list.size() - 1)[1] = val;
                } else {//否则,构建新区间添加到最后
                    int[] arr = {val,val};
                    list.add(arr);
                }
            } else if (insertPosition == 0) {//若插入位置是最前面
                if (val == list.get(0)[0] - 1) {//若当前的第一个区间的左边的值-1 刚好等于val,则将当前区间的左侧的值修改为val;
                    list.get(0)[0] = val;
                } else {//否则,构建新区间添加到最前面
                    int[] arr = {val,val};
                    list.add(0, arr);
                }
            } else if (insertPosition > 0) {//中间
                if (val == list.get(insertPosition)[0] - 1 && val == list.get(insertPosition - 1)[1] + 1) {//若当前插入位置的左侧区间的右值+1 等于val 且 右侧区间的左值-1 等于val,则将两个区间合并。
                    int index = insertPosition - 1;
                    int[] front = list.get(index);
                    int[] behind = list.get(insertPosition);
    
                    list.remove(index);
                    list.remove(index);
    
                    int[] arr = {front[0],behind[1]};
                    list.add(index, arr);
                } else if (val == list.get(insertPosition)[0] - 1) {//若右侧区间的左值-1 等于val,则修改它。
                    list.get(insertPosition)[0] = val;
                } else if (val == list.get(insertPosition - 1)[1] + 1) {//若 左侧区间的右值+1 等于val 则修改它
                    list.get(insertPosition - 1)[1] = val;
                } else {//否则,构建新区间插入
                    int[] arr = {val,val};
                    list.add(insertPosition, arr);
                }
            }
        }
    
        public int[][] getIntervals() {
            int[][] result = new int[list.size()][];
    
            for (int i = 0; i < list.size(); i++) {
                result[i] = list.get(i);
            }
            return result;
        }
    
        private int findInsertPosition(int val) {
            int left = 0;
            int right = list.size();
    
            while (left < right) {
                int mid = (left + right) / 2;
                if (val >= list.get(mid)[0] && val <= list.get(mid)[1]) return -1;//当前val已经属于某一个区间,返回-1
    
                if (val < list.get(mid)[0]) right = mid;
                else if (val > list.get(mid)[1]) left = mid + 1;
            }
    
            return left;
        }
    }
    
  • 分析

    1. 第一次添加数字的时候,直接将这个数字作为独立区间,添加到区间列表中。
    2. 若不是第一次,则通过二分查找计算插入的位置。
    3. 计算出插入的位置有三种
      1. 添加到区间的末尾
        1. 看原来的区间列表的最后一个的右侧的值+1是否等于准备添加的val,如果等于,则修改这个右侧的值为val
        2. 若不等于,则将当前添加的val作为独立的区间添加到表尾。
      2. 添加到区间的开头
        1. 看原来区间列表的首个区间的左侧的值-1是否等于准备添加的val,若等于,则修改这个左侧的值为val。
        2. 若不等于,则将当前添加的val作为独立的区间添加到表头。
      3. 添加到区间的中间
        1. 有三种清空,
          1. 合并插入位置的左右区间,
          2. 和左侧区间合并
          3. 和右侧的区间合并
  • 提交结果

    在这里插入图片描述

354. 俄罗斯套娃信封问题

给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

说明:
不允许旋转信封。

在这里插入图片描述

  • 解答

    public int maxEnvelopes(int[][] envelopes) {
            Arrays.sort(envelopes, new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    return o1[0] == o2[0] ? o2[1] - o1[1] : o1[0] - o2[0];
                }
            });
            int[] height = new int[envelopes.length];
            for (int i = 0; i < envelopes.length; i++) {
                height[i] = envelopes[i][1];
            }
            return lengthOfLIS(height);
        }
    
        public int lengthOfLIS(int[] nums) {
            int len = nums.length;
            if (len <= 1) {
                return len;
            }
            int[] tail = new int[len];//用于记录最长的上升子序列
            tail[0] = nums[0];
            int end = 0;
    
            for (int i = 1; i < len; i++) {
                if (nums[i] > tail[end]) {//若当前的值大于序列的最后一位,则直接加入,长度+1
                    end++;
                    tail[end] = nums[i];
                } else {//否则从中tail中找到第一个比nums[i]大的数字,替换它。
                    int left = 0;
                    int right = end;
                    while (left < right) {//二分查找
                        int mid = left + ((right - left) >>> 1);
                        if (tail[mid] < nums[i]) {
                            left = mid + 1;
                        } else {
                            right = mid;
                        }
                    }
                    tail[left] = nums[i];
                }
            }
            end++;
            return end;
        }
    
  • 分析

    1. 将二维数组,按照第一维度升序,若第一位相同,则第二维度降序的规则排序。

    2. 这样问题就变成了最长上升子序列的问题。然后就用第300题的解法即可。

  • 提交结果
    在这里插入图片描述

355. 设计推特

设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文。你的设计需要支持以下的几个功能:

  1. postTweet(userId, tweetId): 创建一条新的推文
  2. getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由用户关注的人或者是用户自己发出的。推文必须按照时间顺序由最近的开始排序。
  3. follow(followerId, followeeId): 关注一个用户
  4. unfollow(followerId, followeeId): 取消关注一个用户

在这里插入图片描述

  • 解答

    class Twitter {
        int timestamp;
        Map<Integer, List<int[]>> tweets;
        Map<Integer, Set<Integer>> followers;
        /** Initialize your data structure here. */
        public Twitter() {
            timestamp = 0;
            tweets = new HashMap();
            followers = new HashMap();
        }
        
        /** Compose a new tweet. */
        public void postTweet(int userId, int tweetId) {
            timestamp++;//表示发布的时间 越大,就是最近发布的
            List<int[]> list = tweets.get(userId);
            if(list == null){
                list = new ArrayList<>();
            }
            list.add(new int[]{timestamp, tweetId});
            tweets.put(userId, list);
            //自己关注自己,以便后面返回信息流
            follow(userId, userId);
                    
        }
        
        /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
        public List<Integer> getNewsFeed(int userId) {
            List<Integer> res = new ArrayList<>();//保存本人及关注者的前10条推特     
            List<int[]> total = new ArrayList<>(); //本人及关注者的集合所有推特
    
            Set<Integer> fs = followers.get(userId);
            if(fs != null){
                for(int f: fs){
                    List<int[]> temp = tweets.getOrDefault(f, new ArrayList<>());
                    total.addAll(temp);
                }
            }
            
            //将所有tweet放入大顶堆
            PriorityQueue<int[]> pq = getPq();
            for(int[] i: total){
                pq.offer(i);
            }
            
            //返回10个最近的tweet
            for(int i=0; i<10 && !pq.isEmpty(); i++){
                int[] tweet = pq.poll();
                res.add(tweet[1]);
            }
            return res;
        }
        
        /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
        public void follow(int followerId, int followeeId) {
            Set<Integer> followSet = followers.get(followerId);
            if(followSet == null){
                followSet = new HashSet<>();            
            }
            followSet.add(followeeId);
            followers.put(followerId, followSet);
        }
        
        /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
        public void unfollow(int followerId, int followeeId) {
            Set<Integer> followSet = followers.get(followerId);
            if(followerId == followeeId || followSet == null){
                return;
            }else{
                followSet.remove(followeeId);
            }
             
        }
    
        //返回一个大顶堆
        private PriorityQueue<int[]> getPq(){
            return new PriorityQueue<>(new Comparator<int[]>(){
                    public int compare(int[] n1, int[] n2){
                        return n2[0] - n1[0];
                    }
                });
        }
    }
    
  • 分析

    1. in t timestamp表示时间戳,记录文章发布的时间,数字越大,表示最近发布。
    2. Map<Integer, List<int[]>> tweets 表示用户及其对应的推特列表。用户的id作为key,他发布的推特集合作为value。每一篇推特以2维数组构成,第一维度表示时间戳,第二维度表示推特的ID
    3. Map<Integer, Set> followers 表示用户和他关注的用户集合。用户的id作为key,他关注的其他用户的集合作为value。
    4. postTweet 发布推特,时间戳+1,表示最新的一篇推特。获取用户对应的推特列表。如果为空,则新建列表。然后将时间戳和推特id组成一个数组放到推特列表中。并将用户关注自己。方便之后的操作。
    5. getNewsFeed 获取自己及关注者最近的10条消息。利用大顶堆,将自己和关注的用户的推特列表,全部放入到大顶堆中。然后从堆顶取出10条数据,就是最近的10条推特。
    6. follow 关注用户,首先获取当前用户id的关注集合。如果集合为空则新建一个集合。然后将新关注的用户添加到集合中。再将新的结果,用户和他对应的关注集合放到followers中。
    7. unfollow 获取用户id的关注集合。然后从集合中删除这个取消关注的用户id。
  • 提交结果
    在这里插入图片描述

357. 计算各个位数不同的数字个数

给定一个非负整数 n,计算各位数字都不同的数字 x 的个数,其中 0 ≤ x < 10n 。

在这里插入图片描述

  • 解答

    public int countNumbersWithUniqueDigits(int n) {
            if(n == 0) return 1;
            if(n == 1) return 10;
            int result = 91;
            int res = 81;
            int p = 8;
            for(int i = n; i > 2;i--){
                res *= p--;
                result += res;
            }
            return result;
        }
    
  • 分析

    1. 这题目是有规律可循的。
    2. 1个数字的时候是10
    3. 2个数字的时候是10 + 81
    4. 3个数字的时候是10 + 81 + 81 * 8
    5. 4个数字的时候是10 + 81 + 81 * 8 + 81 * 8 * 7
    6. 所以就很简单了 根据这个规则写出程序。
  • 提交结果

    在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值