LeetCode刷题笔记(Java)---更新至350题

前言

需要开通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. 当一个指针超过了数组的界限则停下。
  • 提交结果

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

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

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

猜你喜欢

转载自blog.csdn.net/gongsenlin341/article/details/108593203