Leetcode 编程能力入门徽章最佳实践
基本数据类型
1523. 在区间范围内统计奇数数目
思路一:
- [low, high]上循环遍历
- 判断是不是奇数 <=> 是否能被2整除
- 返回函数为int,全局累加
class Solution {
public int countOdds(int low, int high) {
int ans = 0;
for(int i = low; i <=high; i++ ){
if (i % 2 != 0 ) ans++;
}
return ans;
}
}
但是超时了。。。时间复杂度O(n)
所以我们需要判断如何准确用公式总结问题的规律,[3, 7]有三个奇数,
class Solution {
public int countOdds(int low, int high) {
return (high+1 >> 1) - (low >> 1);
}
}
- Arrays内置排序+遍历的方法
- 确定边界,排序后的第二个元素到倒数第二个
- sum为double类型,自动向上转型
class Solution {
public double average(int[] salary) {
int length = salary.length;
int n = length - 2;
double sum = 0;
Arrays.sort(salary);
for (int i = 1; i <= n; i++) {
sum += salary[i];
}
return sum/n;
}
}
但是排序对于空间复杂度要求较高,只击败了5%的用户
思路二:
- 用整数默认最大值初始化全局最小值,整数默认最小值初始化全局最大值,设置全局累加值sum
- 遍历的过程中更新最小值和最大值
- 用公式(sum-min-max)/(length-2)返回结果
class Solution {
public double average(int[] salary) {
double sum = 0;
double maxValue = Integer.MIN_VALUE, minValue = Integer.MAX_VALUE;
for (int num : salary) {
sum += num;
maxValue = Math.max(maxValue, num);
minValue = Math.min(minValue, num);
}
return (sum - maxValue - minValue) / (salary.length - 2);
}
}
运算符
191. 位1的个数
思路:
- int默认是有符号数,因此无法用取余进行操作,需要用按位与进行判别当前位是不是1,如果是结果就加上1,否则加0
- 每次右移1位
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int ans = 0;
for (int i = 1; i <= 32; i++){
ans += n&1;
n >>= 1;
}
return ans;
}
}
1281. 整数的各位积和之差
思路:
- 取得十进制数每位上的数字(从后往前取)
- 算得累积, 和累加和
- 返回积与和的差值
class Solution {
public int subtractProductAndSum(int n) {
int area = 1;
int sum = 0;
while (n>0){
int p = n%10;
area *= p;
sum += p;
n /= 10;
}
return area-sum;
}
}
条件语句
976. 三角形的最大周长
思路:
- 排好序从后往前找
- 如果能构成三角形,则返回周长
- 否则往前移一位
- 如果检索到开头,没有能构成三角形的,则返回0
class Solution {
public int largestPerimeter(int[] A) {
Arrays.sort(A);
for (int i = A.length - 1; i >= 2; --i) {
if (A[i - 2] + A[i - 1] > A[i]) {
return A[i - 2] + A[i - 1] + A[i];
}
}
return 0;
}
}
- 需要两个确据变量最短曼哈顿距离的数组下标和最短曼哈顿距离
- 遍历二维数组
- 判断是不是有效点
- 判断有效点的曼哈顿距离是否小于当前最短曼哈顿距离,如果是的话更新最短曼哈顿距离的数组下标和最短曼哈顿距离
- 最终遍历完返回最短曼哈顿距离的数组下标
class Solution {
public int nearestValidPoint(int x, int y, int[][] points) {
int minIndex = -1;
int minJuLi = Integer.MAX_VALUE;
for(int i=0;i<points.length;i++){
if(x==points[i][0]||y==points[i][1]){ //有效点
int res = Math.abs(x-points[i][0])+Math.abs(y-points[i][1]);
if(res<minJuLi){
minJuLi = res;
minIndex = i;
}
}
}
return minIndex;
}
}
循环
1822. 数组元素积的符号
思路:
- 用异或进行进行取反,目的是为了保留符号位,同号得正(0),异号得负(1)
class Solution {
public int arraySign(int[] nums) {
// 相乘的符号
int ans = 0;
for (int i : nums) {
if (i == 0) return 0;
ans ^= i;
}
return ans >= 0? 1: -1; // 大于等于0的结果都是正数
}
}
class Solution {
public int arraySign(int[] nums) {
int res = 1;
for (int i : nums) {
if (i == 0) return 0;
if (i < 0) res *= -1;
if (i> 0) res *= 1;
}
return res;
}
}
1502. 判断能否形成等差数列
思路:
class Solution {
public boolean canMakeArithmeticProgression(int[] arr) {
Arrays.sort(arr);
int diff = arr[1] -arr[0];
int i = 0;
while (i < arr.length-1) {
if (arr[i+1] == (i+1) * diff + arr[0]) i++;
else return false;
}
return true;
}
}
202. 快乐数
思路:
- 使用 “快慢指针” 思想,找出循环:“快指针” 每次走两步,“慢指针” 每次走一步,当二者相等时,即为一个循环周期。此时,判断是不是因为 1 引起的循环,是的话就是快乐数,否则不是快乐数。
注意:此题不建议用集合记录每次的计算结果来判断是否进入循环,因为这个集合可能大到无法存储;另外,也不建议使用递归,同理,如果递归层次较深,会直接导致调用栈崩溃。不要因为这个题目给出的整数是 int 型而投机取巧。
public class Solution {
public int squareSum(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
public boolean isHappy(int n) {
int slow = n, fast = squareSum(n);
while (slow != fast){
slow = squareSum(slow);
fast = squareSum(squareSum(fast));
};
return slow == 1;
}
}
class Solution {
public boolean areAlmostEqual(String s1, String s2) {
int i = 0;
int count = 0;
HashMap<Character, Character> dict = new HashMap<>();
while (i < s1.length()){
if (count > 2) return false;
if (s1.charAt(i) != (s2.charAt(i))) {
if (dict.containsKey(s2.charAt(i)) && s1.charAt(i) == dict.get(s2.charAt(i)))
dict.remove(s2.charAt(i));
else
dict.put(s1.charAt(i), s2.charAt(i));
count ++;
}
i++;
}
if (dict.size() == 0) return true;
else return false;
}
}
函数
class Solution {
public List<Integer> preorder(Node root) {
transverse(root);
return res;
}
List<Integer> res = new LinkedList<>();
void transverse(Node root){
if(root == null) return;
res.add(root.val);
for (Node child: root.children){
transverse(child);
}
}
}
496. 下一个更大元素 I
单调栈模板 实现了一个计算下一个更大元素的函数,这里可以直接复用。因为题目说 nums1 是 nums2 的子集,那么我们先把 nums2 中每个元素的下一个更大元素算出来存到一个映射里,然后再让 nums1 中的元素去查表即可。
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
// 记录 nums2 中每个元素的下一个更大元素
int[] greater = nextGreaterElement(nums2);
// 转化成映射:元素 x -> x 的下一个最大元素
HashMap<Integer, Integer> greaterMap = new HashMap<>();
for (int i = 0; i < nums2.length; i++) {
greaterMap.put(nums2[i], greater[i]);
}
// nums1 是 nums2 的子集,所以根据 greaterMap 可以得到结果
int[] res = new int[nums1.length];
for (int i = 0; i < nums1.length; i++) {
res[i] = greaterMap.get(nums1[i]);
}
return res;
}
// 计算 nums 中每个元素的下一个更大元素
int[] nextGreaterElement(int[] nums) {
int n = nums.length;
// 存放答案的数组
int[] res = new int[n];
Stack<Integer> s = new Stack<>();
// 倒着往栈里放
for (int i = n - 1; i >= 0; i--) {
// 判定个子高矮
while (!s.isEmpty() && s.peek() <= nums[i]) {
// 矮个起开,反正也被挡着了。。。
s.pop();
}
// nums[i] 身后的下一个更大元素
res[i] = s.isEmpty() ? -1 : s.peek();
s.push(nums[i]);
}
return res;
}
}
// 详细解析参见:
// https://labuladong.github.io/article/?qno=496
1232. 缀点成线

int deltaX = coordinates[0][0], deltaY = coordinates[0][1];
int n = coordinates.length;
for (int i = 0; i < n; i++) {
coordinates[i][0] -= deltaX;
coordinates[i][1] -= deltaY;
}
int A = coordinates[1][1], B = -coordinates[1][0];
for (int i = 2; i < n; i++) {
int x = coordinates[i][0], y = coordinates[i][1];
if (A * x + B * y != 0) {
return false;
}
}
return true;
class Solution {
public int sumOddLengthSubarrays(int[] arr) {
int sum = 0;
int n = arr.length;
for (int i = 0; i < n; i++) {
int leftCount = i, rightCount = n - i - 1;
int leftOdd = (leftCount + 1) / 2;
int rightOdd = (rightCount + 1) / 2;
int leftEven = leftCount / 2 + 1;
int rightEven = rightCount / 2 + 1;
sum += arr[i] * (leftOdd * rightOdd + leftEven * rightEven);
}
return sum;
}
}
283. 移动零
思路:
可以直接复用 27. 移除元素 的解法,先移除所有 0,然后把最后的元素都置为 0,就相当于移动 0 的效果。
class Solution {
public void moveZeroes(int[] nums) {
int slow = 0, fast = 0;
while(fast<nums.length){
if(nums[fast]!=0) {
nums[slow] = nums[fast];
slow++;
}
fast++;
}
while(slow<nums.length){
nums[slow] = 0;
slow++;
}
}
}
class Solution {
public int maximumWealth(int[][] accounts) {
int max = Integer.MIN_VALUE;
for (int[] i: accounts){
int sum = 0;
for (int j: i){
sum += j;
}
max = Math.max(max, sum);
}
return max;
}
}
数组
class Solution {
public int diagonalSum(int[][] mat) {
int ans = 0;
int n = mat.length;
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
if (j == i || j == n - i - 1)
ans += mat[i][j];
}
}
return ans;
}
}
class Solution {
public int[][] matrixReshape(int[][] mat, int r, int c) {
int m = mat.length;
int n = mat[0].length;
if (m * n != r * c) {
return mat;
}
int[][] res = new int[r][c];
int a = 0;
int b = 0;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (b >= n) {
b = 0;
a++;
}
res[i][j] = mat[a][b];
b++;
}
}
return res;
}
}
字符串
class Solution {
public String mergeAlternately(String word1, String word2) {
int len1 = word1.length();
int len2 = word2.length();
char [] ca = new char[len1+len2];
int p = 0;
int p1 = 0;
while(p < ca.length) {
if(len1 < len2 && p1 >= len1) {
ca[p] = word2.charAt(p1);
}
else if(len1 > len2 && p1 >= len2) {
ca[p] = word1.charAt(p1);
} else{
ca[p] = word1.charAt(p1);
ca[++p] = word2.charAt(p1);
}
p++;
p1++;
}
return new String(ca);
}
}
class Solution {
public String interpret(String command) {
return command.replace("()", "o").replace("(al)", "al");
}
}
class Solution {
public char findTheDifference(String s, String t) {
int as = 0, at = 0;
for (int i = 0; i < s.length(); ++i) {
as += s.charAt(i);
}
for (int i = 0; i < t.length(); ++i) {
at += t.charAt(i);
}
return (char) (at - as);
}
}
class Solution {
public String toLowerCase(String s) {
return s.toLowerCase();
}
}
class Solution {
public String freqAlphabets(String s) {
StringBuilder ans = new StringBuilder();
for(int i = 0; i < s.length(); i++) {
if (s.indexOf('#', i) - i ==2 ) {
ans.append((char)(Integer.parseInt(s.substring(i,i+2))+96));
i+=2;
} else {
ans.append((char)(96+(s.charAt(i)-'0')));
}
}
return ans.toString();
}
}
class Solution {
public boolean isAlienSorted(String[] words, String order) {
int[] index = new int[26];
for (int i = 0; i < order.length(); ++i) {
index[order.charAt(i) - 'a'] = i;
}
for (int i = 1; i < words.length; i++) {
boolean valid = false;
for (int j = 0; j < words[i - 1].length() && j < words[i].length(); j++) {
int prev = index[words[i - 1].charAt(j) - 'a'];
int curr = index[words[i].charAt(j) - 'a'];
if (prev < curr) {
valid = true;
break;
} else if (prev > curr) {
return false;
}
}
if (!valid) {
/* 比较两个字符串的长度 */
if (words[i - 1].length() > words[i].length()) {
return false;
}
}
}
return true;
}
}
链表 & 树
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public int getDecimalValue(ListNode head) {
int ans = head.val;
while (head.next!=null) {ans <<= 1; head = head.next; ans+=head.val;}
return ans;
}
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
// 快慢指针初始化指向 head
ListNode slow = head, fast = head;
// 快指针走到末尾时停止
while (fast != null && fast.next != null) {
// 慢指针走一步,快指针走两步
slow = slow.next;
fast = fast.next.next;
}
// 慢指针指向中点
return slow;
}
}
104. 二叉树的最大深度
思路:
动态规划
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
int leftMax = maxDepth(root.left);
int rightMax = maxDepth(root.right);
return 1+Math.max(leftMax, rightMax);
}
}
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
transverse(root);
return sum;
}
int sum = 0;
void transverse(TreeNode root){
if (root == null) return;
if (root.left != null && root.left.left == null && root.left.right == null) {
sum += root.left.val;
}
transverse(root.left);
transverse(root.right);
}
}
容器&库
class Solution {
public int[] sortByBits(int[] arr) {
int[] map = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
map[i] = Integer.bitCount(arr[i]) * 10000000 + arr[i];
}
Arrays.sort(map);
for (int i = 0; i < map.length; i++) {
map[i] = map[i] % 10000000;
}
return map;
}
}
class MyQueue {
private Stack<Integer> s1, s2;
public MyQueue() {
s1 = new Stack<Integer>();
s2 = new Stack<Integer>();
}
public void push(int x) {
s1.push(x);
}
public int pop() {
peek();
return s2.pop();
}
public int peek() {
if(s2.isEmpty()){
while(!s1.isEmpty())
s2.push(s1.pop());
}
return s2.peek();
}
public boolean empty() {
return s1.isEmpty() && s2.isEmpty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
class Solution {
public boolean isAnagram(String s, String t) {
int [] cnt = new int[26];
if (s.length() != t.length()) return false;
else {
for (int i = 0; i < s.length(); i++){
cnt[s.charAt(i)-'a']++;
}
for (int i = 0; i < t.length(); i++) {
cnt[t.charAt(i)-'a']--;
if (cnt[t.charAt(i)-'a'] < 0) return false;
}
return true;
}
}
}
class Solution {
public boolean containsDuplicate(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++){
if (set.contains(nums[i])) return true;
set.add(nums[i]);
}
return false;
}
}
类 & 对象
class ParkingSystem {
Map<Integer, Integer> map = new HashMap<>();
public ParkingSystem(int _big, int _medium, int _small) {
map.put(1, _big);
map.put(2, _medium);
map.put(3, _small);
}
public boolean addCar(int ct) {
if (map.get(ct) > 0) {
map.put(ct, map.get(ct) - 1);
return true;
}
return false;
}
}
/**
* Your ParkingSystem object will be instantiated and called as such:
* ParkingSystem obj = new ParkingSystem(big, medium, small);
* boolean param_1 = obj.addCar(carType);
*/
class NumArray {
private int[] preSum;
public NumArray(int[] nums) {
preSum = new int[nums.length+1];
for(int i = 1; i < preSum.length; i++){
preSum[i] = preSum[i-1] + nums[i-1];
}
}
public int sumRange(int left, int right) {
return preSum[right + 1] - preSum[left];
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(left,right);
*/