力扣刷题(复习版1)

题目:最大重复子字符串

原题链接:最大重复子字符串
在这里插入图片描述

题解

方法:暴力延长word的重复次数并比较,用contains()函数

 public static int maxRepeating(String sequence, String word) {
     int maxRepeat = 0;
     StringBuilder repeatedWord = new StringBuilder(word);

     // 循环尝试增加word的重复次数,直到不再是子字符串
     while (sequence.contains(repeatedWord)) {
         maxRepeat++;
         repeatedWord.append(word);
     }

     return maxRepeat;
 }

题目: 面试题 16.07. 最大数值

原题链接: 面试题 16.07. 最大数值

题解

方法:通过计算两个整数差值的符号位

表达式 a * (1 - sign) + b * sign 能够实现两个值的二选一效果

 public int maximum(int a, int b) {
     long diff = (long)a - (long)b;
     long sign = (diff >>> 63) & 1;
     return (int)(a * (1 - sign) + b * sign);
 }

题目: 最大字符串配对数目

原题链接: 最大字符串配对数目
在这里插入图片描述

在这里插入图片描述

题解

public static int maximumNumberOfStringPairs(String[] words) {
      HashSet<String> set = new HashSet<>();
      int count = 0;
      for (String word : words) {
          String reversed = "" + word.charAt(1) + word.charAt(0);
          // 检查反转字符串是否已经存在于 set 中
          if (set.contains(reversed)) {
              count++;
          }
          set.add(word);
      }
      return count;
  }

题目: 字符串中第二大的数字

原题链接: 字符串中第二大的数字
在这里插入图片描述

题解

方法1:

 public static int secondHighest(String s) {
     Set<Integer> set = new HashSet<>();
     for (char c : s.toCharArray()) {
         if (Character.isDigit(c)) {
             set.add(c - '0');
         }
     }
     int firstMax = -1;
     int secondMax = -1;
     for (Integer i : set) {
         if (i > firstMax) {
             secondMax = firstMax;
             firstMax = i;
         } else if (i > secondMax && i < firstMax) {
             secondMax = i;
         }
     }
     return secondMax;
 }

方法2:
先找到最大值删除,如果set不为空,继续寻找最大值(答案)

 public static int secondHighest11(String s) {
     Set<Integer> set = new HashSet<>();
     for (char c : s.toCharArray()) {
         if (Character.isDigit(c)) {
             set.add(c - '0');
         }
     }
     int maxValue = -1;
     for (Integer i : set) {
         if (i > maxValue) {
             maxValue = i;
         }
     }
     set.remove(maxValue);
     if (set.size() == 0) return -1;
     maxValue = -1;
     for (Integer i : set) {
         if (i > maxValue) {
             maxValue = i;
         }
     }
     return maxValue;
 }

题目: 统计最大组的数目

原题链接: 统计最大组的数目
在这里插入图片描述

题解

方法:利用 map 将相同的数位和作为键(哈希表)

public static int sumDigit(int i) {
    int res = 0;
    while (i > 0) {
        res += i % 10;
        i /= 10;
    }
    return res;
}

public static int countLargestGroup(int n) {
    int maxCnt = 0;
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int i = 1; i <= n; i++) {
        int sum = sumDigit(i);
        int count = map.getOrDefault(sum, 0) + 1;
        map.put(sum, count);
        maxCnt = Math.max(maxCnt, count);
    }
    
    int res = 0;
    for (Integer value : map.values()) {
        if (value == maxCnt) {
            res++;
        }
    }
    return res;
}

题目: 删除每行中的最大值

原题链接: 删除每行中的最大值
在这里插入图片描述

题解

方法:通过逐列查找每一行未使用的最大值,并将其标记为已使用,然后将每列的最大值累加得到最终结果。主要利用 used 数组来跟踪已经处理过的元素

public boolean[][] used = new boolean[51][51];

 // 找到一行中最最大的元素  并标记已处理
 public int findMaxByRow(int[][] grid, int row) {
     int maxValue = -1;
     int maxIndex = -1;
     for (int i = 0; i < grid[0].length; i++) {
         if (!used[row][i] && grid[row][i] > maxValue) {
             maxValue = grid[row][i];
             maxIndex = i;
         }
     }
     if (maxIndex != -1) {
         used[row][maxIndex] = true;
     }
     return maxValue;
 }

 public int deleteGreatestValue(int[][] grid) {
     int res = 0;
     for (int j = 0; j < grid[0].length; j++) { 
         int maxValue = -1;
         for (int i = 0; i < grid.length; i++) { 
             int maxByRow = findMaxByRow(grid, i);
             if (maxValue < maxByRow)
                 maxValue = maxByRow;
         }
         res += maxValue;
     }
     return res;
 }

题目: 二叉树的所有路径

原题链接: 二叉树的所有路径
在这里插入图片描述

题解

方法:创建两个队列,一个用于存储当前节点 (nodeQueue),另一个用于存储从根节点到当前节点的路径 (pathQueue)。将根节点和路径 “root.val” 入队。

先去看一下二叉树层次遍历,然后看这个题,就很简单了

 public List<String> binaryTreePaths(TreeNode root) {
     List<String> paths = new ArrayList<String>();
     if (root == null) {
         return paths;
     }
     Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
     Queue<String> pathQueue = new LinkedList<String>();

     nodeQueue.offer(root);
     pathQueue.offer(Integer.toString(root.val));

     while (!nodeQueue.isEmpty()) {
         TreeNode node = nodeQueue.poll();
         String path = pathQueue.poll();

         if (node.left == null && node.right == null) {
             paths.add(path);
         } else {
             if (node.left != null) {
                 nodeQueue.offer(node.left);
                 pathQueue.offer(new StringBuffer(path).append("->").append(node.left.val).toString());
             }

             if (node.right != null) {
                 nodeQueue.offer(node.right);
                 pathQueue.offer(new StringBuffer(path).append("->").append(node.right.val).toString());
             }
         }
     }
     return paths;
 }

题目: 七进制数

原题链接: 七进制数
在这里插入图片描述

题解

方法:除7取于法,余数倒着写

 public static String convertToBase7(int num) {
     if (num == 0) return "0";
     StringBuilder res = new StringBuilder();
     int flag = num < 0 ? -1 : 1;
     num = Math.abs(num);
     while (num > 0) {
         res.append(num % 7);
         num /= 7;
     }
     return flag == 1 ? res.reverse().toString() : "-" + res.reverse().toString();
 }

题目: N 叉树的最大深度

原题链接: N 叉树的最大深度
在这里插入图片描述

题解

方法1:广度优先搜索
在每次进入 while 循环时,首先获取 queue 中的节点数量,这代表当前层的节点数。接着,逐一处理这些节点,将它们的子节点添加到 queue 中

public int maxDepth(Node root) {
    if (root == null) return 0;
    int res = 0;
    LinkedList<Node> queue = new LinkedList<>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        res += 1;
        int size = queue.size();
        while (size > 0) {
            Node node = queue.poll();
            queue.addAll(node.children);
            size--;
        }
    }
    return res;
}

方法2: 深度优先搜索

 public int maxDepth(Node root) {
     if (root == null) return 0;
     int maxDepth = 0;
     List<Node> children = root.children;
     for (Node child : children) {
         int childDepth = maxDepth(child);
         maxDepth = Math.max(maxDepth, childDepth);
     }

     return maxDepth+1;
 }

题目: 反转字符串中的单词 III

原题链接: 反转字符串中的单词 III

在这里插入图片描述

题解

方法:主要通过 StringBuilder 的 reverse() 方法来反转每个单词

public String reverseWords(String s) {
    String[] words = s.split(" ");
    StringBuilder res = new StringBuilder();
    for (String word : words) {
        res.append(new StringBuilder(word).reverse()).append(" ");
    }
    return res.toString().trim();
}

题目: 员工奖金 – sql

原题链接: 员工奖金
在这里插入图片描述
在这里插入图片描述

题解

方法:因为奖金为空的也要用null表示。因为加一个:or b.bonus is null

select e.name,b.bonus  
from Employee as e  left join Bonus as b on e.empId=b.empId
where b.bonus  < 1000  or b.bonus is null;

题目: N 叉树的前序遍历

原题链接: N 叉树的前序遍历
在这里插入图片描述

题解

方法:N 叉树的前序遍历与二叉树的前序遍历的思路和方法基本一致

前序遍历:根左右

public List<Integer> preorder(Node root) {
      List<Integer> res = new ArrayList<>();
      helper(root, res);
      return res;
  }

  public void helper(Node root, List<Integer> res) {
      if (root == null) return;
      res.add(root.val); // 访问根元素
      for (Node child : root.children) {
          helper(child, res); 
      }
  }

二叉树前序遍历:

 List<Integer> res = new ArrayList<>();
 // 前序遍历
 public List<Integer> preorderTraversal(TreeNode root) {
     if (root == null) return res;
     res.add(root.val);
     preorderTraversal(root.left);
     preorderTraversal(root.right);
     return res;
 }

题目: N 叉树的后序遍历

原题链接: N 叉树的后序遍历
在这里插入图片描述

题解

 public List<Integer> postorder(Node root) {
     List<Integer> res = new ArrayList<>();
     helper(root, res);
     return res;
 }

 private void helper(Node root, List<Integer> res) {
     if (root == null) return;
     for (Node child : root.children) {
         helper(child, res);
     }
     res.add(root.val);
 }

题目: N 叉树的层序遍历

原题链接: N 叉树的层序遍历
在这里插入图片描述

题解

方法:和二叉树层次遍历相同,借助队列queue

 public List<List<Integer>> levelOrder(Node root) {
     List<List<Integer>> res = new ArrayList<>();
     if (root == null) return res;
     LinkedList<Node> queue = new LinkedList<>();
     queue.offer(root);
     while (!queue.isEmpty()) {
         int size = queue.size();
         ArrayList<Integer> list = new ArrayList<>();
         while (size > 0) {
             Node node = queue.poll();
             list.add(node.val);
             for (Node child : node.children) {
                 queue.offer(child);
             }
             size--;
         }
         res.add(list);
     }
     return res;
 }

题目: 最长和谐子序列

原题链接: 最长和谐子序列
在这里插入图片描述

题解

方法:这个方法利用 HashMap 记录每个数字的出现次数,并通过检查每个数字和它的下一个数字是否同时存在来寻找和谐子数组的最大长度。

public static int findLHS(int[] nums) {
      int res = 0;
      HashMap<Integer, Integer> map = new HashMap<>();
      for (int num : nums) {
          map.put(num, (1 + map.getOrDefault(num, 0)));
      }

      for (Integer i : map.keySet()) {
          if (map.containsKey(i + 1)) {
              res = Math.max(res, map.get(i) + map.get(i + 1));
          }
      }
      return res;
  }

题目: 种花问题

原题链接: 种花问题
在这里插入图片描述

题解

方法:通过遍历花坛,检查每个位置是否可以放置花朵,确保前后位置均为空。它在合适的位置放置花朵,并计算可以放置的总花朵数,最终判断是否能满足所需的花朵数量。

 public boolean canPlaceFlowers(int[] flowerbed, int n) {
     int count = 0;
     for (int i = 0; i < flowerbed.length; i++) {
         // 如果当前位置是 0 且前后位置也为空(边界条件也要考虑)
         if (flowerbed[i] == 0 &&
                 (i == 0 || flowerbed[i - 1] == 0) &&
                 (i == flowerbed.length - 1 || flowerbed[i + 1] == 0)) {

             // 放置花朵
             flowerbed[i] = 1;
             count++;
         }
     }
     return count >= n;
 }

题目: 三个数的最大乘积

原题链接: 三个数的最大乘积
在这里插入图片描述

题解

方法:排序

我第一想法没考虑到排序,感觉刷迷糊了😭

 public int maximumProduct(int[] nums) {
     Arrays.sort(nums);
     return Math.max(nums[0] * nums[1] * nums[nums.length - 1], nums[nums.length - 1] * nums[nums.length - 2] * nums[nums.length - 3]);
 }

题目: 二叉树中第二小的节点

原题链接: 二叉树中第二小的节点
在这里插入图片描述

题解

方法1:

public static int findSecondMinimumValue(TreeNode root) {
    HashSet<Integer> set = new HashSet<>();
    helper(root, set);
    if (set.size() < 2) return -1;
    int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
    for (int i : set) {
        if (i < min1) {
            min1 = i;
        }
    }
    set.remove(min1);
    for (int i : set) {
        if (i < min2) {
            min2 = i;
        }
    }
    return min2;
}

public static void helper(TreeNode root, HashSet<Integer> set) {
    if (root == null) return;
    set.add(root.val);
    helper(root.left, set);
    helper(root.right, set);
}

方法:

 public static int findSecondMinimumValue(TreeNode root) {
     if (root == null) return -1;
     // 初始最小值为根节点的值
     int firstMin = root.val;
     // 使用递归找出第二小的值
     return findSecondMinimum(root, firstMin);
 }

 private static int findSecondMinimum(TreeNode root, int firstMin) {
     if (root == null) return -1;
     // 如果当前节点值大于最小值,可能是第二小的值
     if (root.val > firstMin) return root.val;

     // 递归查找左右子树中的第二小值
     int left = findSecondMinimum(root.left, firstMin);
     int right = findSecondMinimum(root.right, firstMin);

     // 处理左右子树的值
     if (left != -1 && right != -1) {
         return Math.min(left, right);
     }
     return Math.max(left, right);
 }

题目: 旋转字符串

原题链接: 旋转字符串
在这里插入图片描述

题解

方法1:将输入字符串s转换为字符链表,然后通过循环将链表的最后一个元素移动到第一个位置,每次旋转后都检查是否与目标字符串goal相等,如果相等则返回true。如果旋转了整个字符串长度次后仍未找到匹配,则返回false。

public boolean rotateString(String s, String goal) {
     if (s.length() != goal.length()) return false;
     LinkedList<Character> list = new LinkedList<>();
     char[] charArray = s.toCharArray();
     for (char c : charArray) {
         list.addLast(c);
     }
     for (int i = 0; i < list.size(); i++) {
         list.addFirst(list.removeLast());
         StringBuilder builder = new StringBuilder();
         list.stream().forEach(builder::append);
         if (builder.toString().equals(goal)) return true;
     }
     return false;
 }

方法2:搜索子字符串
如果将字符串 s 拼接到自身形成 doubled,那么所有可能的旋转版本都将成为 doubled 的子串。

public boolean rotateString(String s, String goal) {
    // 先检查长度是否相同,不同则直接返回 false
    if (s.length() != goal.length()) {
        return false;
    }
    
    // 将 s 重复两次
    String doubled = s + s;
    
    // 检查 goal 是否是 doubleS 的子串
    return doubled.contains(goal);
}

题目: 比较含退格的字符串

原题链接: 比较含退格的字符串
在这里插入图片描述

题解

方法:处理过程中,将每个字符串中的字符按顺序添加到 StringBuilder 中,并且遇到 '#' 时删除最后一个字符。最终,方法通过比较两个处理后的字符串来确定它们是否相等。

 public static boolean backspaceCompare(String s, String t) {
     return extracted(s).equals(extracted(t));
 }

 public static String extracted(String s) {
     StringBuilder res = new StringBuilder();
     for (char c : s.toCharArray()) {
         if (c == '#') {
             if (res.length() > 0) res.deleteCharAt(res.length() - 1);
         } else {
             res.append(c);
         }
     }
     return res.toString();
 }

题目: 和为零的 N 个不同整数

原题链接: 和为零的 N 个不同整数
在这里插入图片描述

题解

方法:

  • 如果 n 是偶数,生成对称的正负数对。
  • 如果 n 是奇数,生成对称的正负数对并在中间加一个 0
public static int[] sumZero(int n) {
     int[] arr = new int[n];
     // 填充数组
     for (int i = 0; i < n / 2; i++) {
         arr[i] = i + 1;       // 生成正数
         arr[n - i - 1] = -(i + 1); // 生成对应的负数
     }
     // 如果 n 是奇数,填入中间的 0
     if (n % 2 != 0) {
         arr[n / 2] = 0;
     }
     return arr;
 }

题目: 日期之间隔几天

原题链接: 日期之间隔几天
在这里插入图片描述

题解

方法: toEpochDay() 方法返回的是从 1970-01-01 开始到指定日期的天数。(1970 年 1 月 1 日被称为“纪元”或“epoch”)

用这个api这道题直接走捷径

 import java.time.LocalDate;
 public int daysBetweenDates(String date1, String date2) {
     LocalDate d1 = LocalDate.parse(date1);
     LocalDate d2 = LocalDate.parse(date2);
     return (int) Math.abs(d1.toEpochDay()-d2.toEpochDay());
 }

题目: 通过翻转子数组使两个数组相等

原题链接: 通过翻转子数组使两个数组相等在这里插入图片描述

题解

方法1:
大意了,没仔细读题,这方法臃肿了。但是发现一个不起眼的错误。

public static boolean canBeEqual(int[] target, int[] arr) {
    Map<Integer, Integer> map = new HashMap<>();
    Set<Integer> set = new HashSet<>();
    for (int i : target) {
        set.add(i);
        map.put(i, map.getOrDefault(i, 0) + 1);
    }

    int cnt = 0;
    Map<Integer, Integer> map1 = new HashMap<>();
    for (int i : arr) {
        map1.put(i, map1.getOrDefault(i, 0) + 1);
    }
    for (Integer i : map.keySet()) {
        if (map1.containsKey(i) && (map.get(i).equals(map1.get(i)))) {
            cnt += 1;
        }
    }
    return cnt == set.size();
}

在这里插入图片描述
当我在力扣上提交,发现就一个通不过,所以我就去本地IDEA调试了下,发现Integer比较出错了。知道这个知识点,但是实际用的适合却忽略了😭

改为 (map.get(i).equals(map1.get(i))),然后就通过了

Integer 对象在一定范围内(-128 到 127)是缓存的,因此在这个范围内的 Integer 对象是相同的。但是,超出这个范围的 Integer 对象则会在不同的对象实例中创建,即使它们的值相等,== 比较也可能会失败。
在这里插入图片描述

方法2:先排序然后比较数组
因为说了数组长度相同,所以直接排序,然后Arrays工具类中equals方法比较即可出答案

Arrays.equals 是一个用于比较两个数组是否相等的静态方法

 public static boolean canBeEqual(int[] target, int[] arr) {
     Arrays.sort(target);
     Arrays.sort(arr);
     return Arrays.equals(target, arr);
 }

在这里插入图片描述

题目: 第 k 个缺失的正整数

原题链接: 第 k 个缺失的正整数
在这里插入图片描述

题解

方法:利用set记录已经存在的

 public int findKthPositive(int[] arr, int k) {
     HashSet<Integer> set = new HashSet<>();
     for (int i : arr) {
         set.add(i);
     }
     int cnt = 0;
     for (int i = 1; i <= arr[arr.length - 1] + k; i++) {
         if (!set.contains(i)) {
             cnt += 1;
             if (cnt == k) {
                 return i;
             }
         }
     }
     return 0;
 }

题目: 千位分隔数

原题链接: 千位分隔数
在这里插入图片描述

题解

在处理字符串时,使用 append 方法通常比 insert 更高效。

方法1:用StringBuilder的insert方法

 public String thousandSeparator(int n) {
     if (n == 0) return "0";
     StringBuilder sb = new StringBuilder();
     int cnt = 0;
     while (n > 0) {
         if (cnt == 3) {
             sb.insert(0, '.');
             cnt = 0;
         }
         sb.insert(0, n % 10);
         cnt += 1;
         n /= 10;
     }
     return sb.toString();
 }

方法2:用StringBuilder的append方法

 public String thousandSeparator(int n) {
     if (n == 0) return "0";
     StringBuilder sb = new StringBuilder();
     int cnt = 0;
     while (n > 0) {
         if (cnt == 3 ) {
             sb.append('.');
             cnt=0;
         }
         sb.append(n % 10);
         n /= 10;
         cnt++;
     }

     return sb.reverse().toString();
 }

总结

  1. 拿到一个题目要认真读题(建议读2遍),没思路可以看一下提示,有时候提示会给你一些解题思路的
  2. 不要被给的输入输出示例迷惑了,有时候会干扰你解题的
好的,关于力扣刷题C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷题中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷题中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷题中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷题中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷题中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷题中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷题中,使用 string 可以方便地处理字符串相关的问题。 9. 注意边界条件:在力扣刷题中,边界条件往往是解决问题的关键。需要仔细分析题目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷题中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值