脚本宝典收集整理的这篇文章主要介绍了《编程能力基础》刷题笔记 1 ~ 20 题,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
刷题代码:https://gitee.com/szluyu99/my-leet-code
题目:896. 单调数列
因为题目看着让人很想递归,先送上个递归做法:(强行递归,必定超时)
/**
* 递归(超时)
*/
function isMonotonic(nums: number[]): boolean {
return nums[0] < nums[nums.length - 1] ?
isMonotonicIncrease(nums) : isMonotonicDecrease(nums)
};
// 递归判断是否单调递
const isMonotonicIncrease = function (nums: number[]): boolean {
if (nums.length == 1) return true
if (nums[0] > nums[1]) return false
return isMonotonicIncrease(nums.slice(1)) ? true : false
}
// 递归判断是否单调减
const isMonotonicDecrease = function (nums: number[]): boolean {
if (nums.length == 1) return true
if (nums[0] < nums[1]) return false
return isMonotonicDecrease(nums.slice(1)) ? true : false
}
—
然后才是正文。
解法1:
nums[0]
和 nums[1]
可以判断这个序列是 递增 还是 递减/**
* 通过 nums[0] 和 nums[nums.length - 1] 判断出增减方向
* 遍历数组一次,两两比较
*/
public boolean isMonotonic1(int[] nums) {
// 先判断 递增 还是 递减
if (nums[0] <= nums[nums.length - 1]) { // 递增
for (int i = 1; i < nums.length; i++)
if (nums[i - 1] > nums[i]) return false;
} else { // 递减
for (int i = 1; i < nums.length; i++)
if (nums[i - 1] < nums[i]) return false;
}
return true;
}
解法2:
public boolean isMonotonic(int[] nums) {
boolean inc = true, dec = true;
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] > nums[i + 1]) inc = false;
if (nums[i] < nums[i + 1]) dec = false;
// 剪枝操作, 已经明确既不递增也不递减, 直接返回 false
if (!inc && !dec) return false;
}
return inc || dec;
}
解法3:然后就是利用语言特性和 API 的做法了,比如 JS
var isMonotonic = function (nums) {
return isSorted(nums) || isSorted(nums.reverse())
}
// 判断是否单调增
function isSorted(nums) {
return nums.slice(1).every((item, i) => nums[i] <= item)
}
题目:28. 实现 strStr()
先来一个每个人必定会尝试一下的解法:库函数
public int strStr(String haystack, String needle) {
return haystack.indexOf(needle);
}
再来个比较常规但是会超时的暴力解法:暴力
public int strStr1(String haystack, String needle) {
if (haystack.length() < needle.length()) return -1;
if (needle.isEmpty()) return 0;
for (int i = 0; i < haystack.length(); i++) {
int tmpIdx = 0;
while (i + tmpIdx < haystack.length()
&& haystack.charAt(i + tmpIdx) == needle.charAt(tmpIdx++))
if (tmpIdx == needle.length()) return i;
}
return -1;
}
然后来个可以正常通过的解法:滑动窗口
public int strStr2(String haystack, String needle) {
if (haystack.length() < needle.length()) return -1;
// 窗口长度
int width = needle.length();
// 当前索引
int idx = 0;
// 只访问不会越界的部分
while (idx + width <= haystack.length()) {
// 找到则返回索引
if (needle.equals(haystack.substring(idx, idx + width)))
return idx;
idx++;
}
return -1;
}
至于其他比较强力的算法如 KMP 等等,待我功力深厚以后再回来将其拿下!
题目:110. 平衡二叉树
解法1:常规思路,先写一个 获取二叉树节点高度 的函数,然后对二叉树进行 遍历 + 判断
const isBalanced = function (root: TreeNode | null): boolean {
if (!root) return true
if (Math.abs(getHeight(root.left) - getHeight(root.right)) > 1)
return false
return isBalanced(root.left) && isBalanced(root.right)
}
// 获取二叉树节点的高度
const getHeight = (root: TreeNode | null) => {
if (!root) return 0
return Math.max(getHeight(root.left), getHeight(root.right)) + 1
}
解法2:这个有点难理解,其实是解法1的升级版
const isBalanced = function (root: TreeNode | null): boolean {
return recur(root) != -1
}
const recur = function (root: TreeNode | null): number {
if (!root) return 0
let left = recur(root.left)
if (left == -1) return -1
let right = recur(root.right)
if (right == -1) return -1
return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1
}
题目:459. 重复的子字符串
这道题比较好想的思路是模拟,但是模拟也是有讲究的,要尽量减少暴力的次数(俗称剪枝)
在我的理解中,剪枝属于一种优化,其实把剪枝部分去掉应该也可以正常运行,但是效率会变低
解法1:模拟 + 剪枝
const repeatedSubstringPattern = function (s: string): boolean {
if (s.length < 2) return false
// 只需要遍历一半即可, 一半以后必然不能重复
for (let i = 1; i <= s.length / 2; i++) {
let sub = s.substring(0, i)
// 剪枝:字符串的长度不是串的整数倍, 必然不满足条件
if (s.length % i != 0) continue
// 剪枝:最后不是以该子串结尾, 必然不满足条件
if (sub != s.substring(s.length - sub.length)) continue
// 利用 repeat API, 查看是否满足满足要求
if (sub.repeat(s.length / sub.length) == s)
return true
}
return false
}
解法2:技巧
这个思路是参考其他大佬的,确实很奇妙,学习了,可以留个印象
简单明了!!关于java两行代码实现的思路来源
[1] s = acd
[2] ss = acdacd
[3] ss.substring(1, ss.length - 1) = cdac (去头去尾)
判断: [3] 中包含 [1] 则满足条件, s = 'acd' 不满足条件
---
[1] s = acaaca
[2] ss = acaacaacaaca
[3] ss.substring(1, ss.length - 1) = caacaacaac (去头去尾)
判断: [3] 中包含 [1] 则满足条件, s = 'acaaca' 满足条件
const repeatedSubstringPattern = function (s: string): boolean {
let ss = s.repeat(2)
return ss.substring(1, ss.length - 1).indexOf(s) != -1
}
题目:150. 逆波兰表达式求值
解法1:用栈模拟,会使这道题万分简单
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (String token : tokens) {
if ("+".equals(token)) {
Integer num1 = stack.pop();
Integer num2 = stack.pop();
stack.push(num2 + num1);
} else if ("-".equals(token)) {
Integer num1 = stack.pop();
Integer num2 = stack.pop();
stack.push(num2 - num1);
} else if ("*".equals(token)) {
Integer num1 = stack.pop();
Integer num2 = stack.pop();
stack.push(num2 * num1);
} else if ("/".equals(token)) {
Integer num1 = stack.pop();
Integer num2 = stack.pop();
stack.push(num2 / num1);
} else {
stack.push(Integer.parseInt(token));
}
}
return stack.pop();
}
代码丑陋,略微优化一下:(效率无影响)
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (String token : tokens) {
if ("+".equals(token))
stack.push(stack.pop() + stack.pop());
else if ("-".equals(token))
stack.push(-stack.pop() + stack.pop());
else if ("*".equals(token))
stack.push(stack.pop() * stack.pop());
else if ("/".equals(token)) {
Integer num1 = stack.pop(), num2 = stack.pop();
stack.push(num2 / num1);
} else
stack.push(Integer.parseInt(token));
}
return stack.pop();
}
解法2:用数组代替栈模拟
class Solution {
public int evalRPN(String[] tokens) {
int[] res = new int[tokens.length];
int cur = 1; // 索引从 - 1 开始, 因为必须放进元素才能开始计算
for (String token : tokens) {
if ("/*-+".contains(token)) {
int b = res[cur--], a = res[cur--];
res[++cur] = calc(a, b, token);
} else
res[++cur] = Integer.parseInt(token);
}
return res[cur];
}
public int calc(int a, int b, String op) {
if (op.equals("+")) return a + b;
else if (op.equals("-")) return a - b;
else if (op.equals("*")) return a * b;
else if (op.equals("/")) return a / b;
else return -1;
}
}
题目:66. 加一
解法1:最朴素的模拟做法,这个基本上是第一反映想到的,速度也可以击败 100%
public int[] plusOne(int[] digits) {
int len = digits.length;
// 1 不会进位的情况(最后一位不为 9)
// 例如: 123 --> 124
if (digits[len - 1] != 9) {
digits[len - 1] += 1;
return digits;
}
// 2 全是9的特殊情况:
// 例如: 999 --> 1000
boolean flag = true; // 是否全是9
for (int i = 0; i < len; i++) {
if (digits[i] != 9) {
flag = false;
break;
}
}
if (flag) {
int[] res = new int[len + 1];
res[0] = 1;
return res;
}
// 3 最后一位是9, 但是不全为 9
// 例如: 129 --> 130
digits[len - 1] += 1;
while (len > 1) {
// 无需进位, 直接跳出返回
if (digits[len - 1] != 10) break;
// 计算进位
digits[len - 1] = 0;
digits[--len - 1] += 1;
}
return digits;
}
解法2:其实是对以上代码的优化
public int[] plusOne(int[] digits) {
for (int i = digits.length - 1; i >= 0; i--) {
// 最后一位不为 9, 直接 + 1 返回结果
if (digits[i] != 9) {
digits[i]++;
return digits;
}
// 最后一位为 9 或 10, 需要进位
digits[i] = 0;
}
// 走完 for 还没有 return, 说明数字全是 9, 直接构造出结果并返回
int[] res = new int[digits.length + 1];
res[0] = 1;
return res;
}
题目:1367. 二叉树中的列表
解法1:一个递归(超时)
boolean isSubPath(ListNode head, TreeNode root) {
if (root == null) return false;
if (head == null) return true;
// 找到了与链表首节点相同的树节点
if (root.val == head.val) {
// 走到链表尾部, 表示已经找到和链表对应的路径
if (head.next == null) return true;
// 沿着这条路径走下去, 能对应上的则返回true
if (root.left != null && head.next.val == root.left.val
&& isSubPath(head.next, root.left))
return true;
if (root.right != null && head.next.val == root.right.val
&& isSubPath(head.next, root.right))
return true;
}
return isSubPath(head, root.left) || isSubPath(head, root.right);
}
解法2:两个递归(可 AC)
class Solution {
boolean isSubPath(ListNode head, TreeNode root) {
if (root == null) return false;
if (dfs(head, root)) return true;
return isSubPath(head, root.left) || isSubPath(head, root.right);
}
boolean dfs(ListNode head, TreeNode root) {
// 链表全部匹配完, 匹配成功
if (head == null) return true;
// 二叉树访问到空节点, 匹配失败
if (root == null) return false;
// 当前二叉树上的节点与链表节点值不相等, 匹配失败
if (root.val != head.val) return false;
return dfs(head.next, root.left) || dfs(head.next, root.right);
}
}
题目:43. 字符串相乘
题目:67. 二进制求和
这题可以根据题意直接模拟,最多也就是代码长点,if 条件多点,先做出来再说!
以下两个解法就是代码长短问题,效率是一样的。
解法1:模拟 + 各种 if + StringBuilder
public String addBinary(String a, String b) {
StringBuilder sb = new StringBuilder();
int carry = 0;
int p1 = a.length(), p2 = b.length();
while (p1 >= 0 || p2 >= 0) {
char ca = (--p1 >= 0) ? a.charAt(p1) : '0';
char cb = (--p2 >= 0) ? b.charAt(p2) : '0';
if (ca == '1' && cb == '1') {
if (carry == 1) sb.insert(0, "1");
else sb.insert(0, "0");
carry = 1;
continue;
}
if (ca == '0' && cb == '0') {
if (carry == 1) sb.insert(0, "1");
else sb.insert(0, "0");
carry = 0;
continue;
}
if (carry == 1) {
sb.insert(0, "0");
carry = 1;
} else {
sb.insert(0, "1");
carry = 0;
}
}
return sb.charAt(0) == '0' ? sb.substring(1).toString() : sb.toString();
}
题解2:善用 'a' - '0'
这种方式转数字,优化代码
public String addBinary(String a, String b) {
StringBuilder sb = new StringBuilder();
int i = a.length() - 1, j = b.length() - 1;
int c = 0; // 进位
while (i >= 0 || j >= 0) {
if (i >= 0) c += a.charAt(i--) - '0';
if (j >= 0) c += b.charAt(j--) - '0';
sb.append(c & 1);
c >>= 1;
}
String res = sb.reverse().toString();
return c > 0 ? "1" + res : res;
}
题目:989. 数组形式的整数加法
这题常规思路是比较容易做出来的,就是从后往前遍历,然后相加,同时保存一个进位,每次注意更新进位的值就行了
基于以上思路,Java 中使用 ArrayList 的话,前插 res.Add(0, val)
效率不如直接后插然后反转。。。
解法1:模拟,用 ArrayList 往后插入数据,然后反转容器
public List<Integer> addToArrayForm(int[] num, int k) {
List<Integer> res = new ArrayList<>();
int carry = 0, len = num.length - 1;
while (len >= 0 || k != 0) {
int n1 = len >= 0 ? num[len--] : 0;
int n2 = k % 10;
k /= 10;
res.add((n1 + n2 + carry) % 10);
carry = n1 + n2 + carry >= 10 ? 1 : 0;
}
if (carry == 1) res.add(1);
Collections.reverse(res);
return res;
}
但是如果使用 LinkedList 的前插 res.addFirst(val)
效果会很快
解法2:模拟,用 LinkedList 直接往前插入数据
public List<Integer> addToArrayForm(int[] num, int k) {
LinkedList<Integer> res = new LinkedList<>();
int carry = 0, len = num.length - 1;
while (len >= 0 || k != 0) {
int n1 = len >= 0 ? num[len--] : 0;
int n2 = k % 10;
k /= 10;
res.addFirst((n1 + n2 + carry) % 10);
carry = n1 + n2 + carry >= 10 ? 1 : 0;
}
if (carry == 1) res.addFirst(1);
return res;
}
解法3:还有很多其他做法,比如将数字转成 int 数组后操作…
public List<Integer> addToArrayForm(int[] num, int k) {
String[] ss = String.valueOf(k).split("");
// string[] => int[]
int[] is = Arrays.stream(ss).mapToInt(Integer::valueOf).toArray();
List<Integer> res = new ArrayList<>();
int carry = 0;
int p1 = num.length - 1, p2 = is.length - 1;
while (p1 >= 0 || p2 >= 0) {
int n1 = p1 >= 0 ? num[p1--] : 0;
int n2 = p2 >= 0 ? is[p2--] : 0;
int sum = (n1 + n2 + carry) % 10;
carry = (n1 + n2 + carry) >= 10 ? 1 : 0;
res.add(0, sum);
}
if (carry == 1) res.add(0, 1);
return res;
}
题目:739. 每日温度
解法1:暴力
public int[] dailyTemperatures(int[] T) {
int[] res = new int[T.length];
for (int i = 0; i < T.length; i++) {
for (int j = i + 1; j < T.length; j++) {
if (T[j] > T[i]) {
res[i] = j - i;
break;
}
}
}
return res;
}
解法2:单调递减栈
注意:Java 中建议使用
Deque
而不是用Stack
public int[] dailyTemperatures(int[] T) {
// 单调递减栈(栈中存储的是下标)
Deque<Integer> stack = new ArrayDeque<>();
int[] res = new int[T.length];
for (int i = 0; i < T.length; i++) {
// 当前元素 > 栈顶下标对应元素
while (!stack.isEmpty() && T[i] > T[stack.peekLast()]) {
int temp = stack.removeLast(); // 获取栈顶下标
res[temp] = i - temp; // 计算下标距离
}
stack.addLast(i); // 当前位置入栈
}
return res;
}
题目:58. 最后一个单词的长度
解法1:暴力使用 API
public int lengthOfLastWord(String s) {
String[] words = s.split("\s+");
return words[words.length - 1].length();
}
解法2:轻度使用 API
public int lengthOfLastWord(String s) {
s = s.trim();
for (int i = s.length() - 1; i >= 0; i--)
if (s.charAt(i) == ' ')
return s.length() - i - 1;
return s.length();
}
解法3:不使用 API
public int lengthOfLastWord(String s) {
int i = s.length() - 1;
// 去除末尾的空字符
while (s.charAt(i) == ' ') i--;
int cnt = 0;
while (i >= 0 && s.charAt(i) != ' ') {
cnt++;
i--;
}
return cnt;
}
题目:48. 旋转图像
解法1:暴力模拟
public void rotate(int[][] matrix) {
int n = matrix.length;
for (int i = 0; i < n / 2; i++) {
for (int j = i; j < n - i - 1; j++) {
// 00 -> 02
// 01 -> 12
int temp = matrix[j][n - i - 1];
matrix[j][n - i - 1] = matrix[i][j];
// 02 -> 22
// 12 -> 21
int temp2 = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = temp;
// 22 -> 20
// 21 -> 10
temp = matrix[n - j - 1][i];
matrix[n - j - 1][i] = temp2;
// 20 -> 00
// 10 -> 01
matrix[i][j] = temp;
}
}
}
优化以上代码:
public void rotate(int[][] matrix) {
int n = matrix.length - 1;
for (int i = 0; i <= matrix.length / 2; i++) {
for (int j = i; j < n - i; j++) {
// 获取各顶点的值
int a = matrix[i][j]; // 左上角
int b = matrix[j][n - i]; // 右上角
int c = matrix[n - i][n - j]; // 右下角
int d = matrix[n - j][i]; // 左下角
// 交换各顶点的值
matrix[i][j] = d;
matrix[j][n - i] = a;
matrix[n - i][n - j] = b;
matrix[n - j][i] = c;
}
}
}
解法2:技巧
public void rotate(int[][] matrix) {
int n = matrix.length;
// 先沿对角线翻转
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 再沿垂直竖线翻转
for (int i = 0; i < n; i++) {
for (int j = 0, k = n - 1; j < k; j++, k--) {
int temp = matrix[i][k];
matrix[i][k] = matrix[i][j];
matrix[i][j] = temp;
}
}
}
题目:1886. 判断矩阵经轮转后是否一致
n x n
矩阵旋转总结:
n x n
矩阵旋转总结:
但是如果不是要一下子求出结果,而是要每个轮流判断,只需要利用转 90 度就行。
本题解法:暴力模拟
转 90 度的两种思路:
public void rotate(int[][] matrix) {
int n = matrix.length - 1;
for (int i = 0; i <= matrix.length / 2; i++) {
for (int j = i; j < n - i; j++) {
// 获取各顶点的值
int a = matrix[i][j]; // 左上角
int b = matrix[j][n - i]; // 右上角
int c = matrix[n - i][n - j]; // 右下角
int d = matrix[n - j][i]; // 左下角
// 交换各顶点的值
matrix[i][j] = d;
matrix[j][n - i] = a;
matrix[n - i][n - j] = b;
matrix[n - j][i] = c;
}
}
}
思路2:技巧,也就是上面的矩阵旋转总结中,沿左上到右下翻转,再沿垂直中线翻转
public void rotate(int[][] matrix) {
int n = matrix.length;
// 先沿对角线翻转
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 再沿垂直竖线翻转
for (int i = 0; i < n; i++) {
for (int j = 0, k = n - 1; j < k; j++, k--) {
int temp = matrix[i][k];
matrix[i][k] = matrix[i][j];
matrix[i][j] = temp;
}
}
}
根据以上的基础,可以知道本题代码为下:
class Solution {
public boolean findRotation(int[][] mat, int[][] target) {
// 不转
if (checkMatrix(mat, target)) return true;
// 转 90 度
rotate(mat);
if (checkMatrix(mat, target)) return true;
// 转 180 度(再转 90 度)
rotate(mat);
if (checkMatrix(mat, target)) return true;
// 转 270 度(再转 90 度)
rotate(mat);
if (checkMatrix(mat, target)) return true;
return false;
}
/**
* 将矩阵旋转 90 度
*/
void rotate(int [][] matrix) {
int n = matrix.length;
// 沿 左上->右下 翻转
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 沿 垂直中线 翻转
for (int i = 0; i < n; i++) {
for (int j = 0, k = n -1; j < k; j++, k--) {
int temp = matrix[i][k];
matrix[i][k] = matrix[i][j];
matrix[i][j] = temp;
}
}
}
/**
* 检查两矩阵是否相等
*/
boolean checkMatrix(int[][] m1, int[][] m2) {
for (int i = 0; i < m1.length; i++) {
for (int j = 0; j < m1[0].length; j++) {
if (m1[i][j] != m2[i][j]) return false;
}
}
return true;
}
}
题目:54. 螺旋矩阵
最朴素易懂的做法:
public List<Integer> spiralOrder(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
List<Integer> res = new ArrayList<>();
int direction = 1; // 1234 - 右下左上
boolean[][] visited = new boolean[m][n]; // 记录访问过的坐标, 防止重复访问
int x = 0, y = 0; // 当前访问坐标
// 初始化第一个位置
res.add(matrix[0][0]);
visited[0][0] = true;
while (res.size() < m * n) {
// 一直往 右 走
while (direction == 1 && y + 1 < n && !visited[x][y + 1]) {
res.add(matrix[x][++y]);
visited[x][y] = true;
}
direction = 2; // 更改方向为 下
// 一直往 下 走
while (direction == 2 && x + 1 < m && !visited[x + 1][y]) {
res.add(matrix[++x][y]);
visited[x][y] = true;
}
direction = 3; // 更改方向为 左
// 一直往 左 走
while (direction == 3 && y - 1 >= 0 && !visited[x][y - 1]) {
res.add(matrix[x][--y]);
visited[x][y] = true;
}
direction = 4; // 更改方向为 上
// 一直往 上 走
while (direction == 4 && x - 1 >= 0 && !visited[x - 1][y]) {
res.add(matrix[--x][y]);
visited[x][y] = true;
}
direction = 1; // 更改方向为 右
}
return res;
}
题目:973. 最接近原点的 K 个点
解法1:自定义排序规则后,利用数组的排序函数
public int[][] kClosest(int[][] points, int k) {
Queue<int[]> queue = new PriorityQueue<>(
Comparator.comparingDouble(o -> o[0] * o[0] + o[1] * o[1]));
queue.addAll(Arrays.asList(points));
int[][] res = new int[k][2];
for (int i = 0; i < k; i++) res[i] = queue.poll();
return res;
}
解法2:利用优先级队列
public int[][] kClosest(int[][] points, int k) {
Queue<int[]> queue = new PriorityQueue<>(
Comparator.comparingDouble(o -> o[0] * o[0] + o[1] * o[1]));
queue.addAll(Arrays.asList(points));
int[][] res = new int[k][2];
for (int i = 0; i < k; i++) res[i] = queue.poll();
return res;
}
对优先级队列做法的优化:只维护 size = k 的优先队列
public int[][] kClosest(int[][] points, int k) {
PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> cmp(a, b));
// 遍历的同时维护 size = k 的优先级队列
for (int i = 0; i < points.length; i++) {
// 堆中元素数量 < k, 直接放入
if (queue.size() < k)
queue.add(points[i]);
// 堆中已经有 k 个元素, 比较堆顶元素和当前遍历元素
else {
int[] temp = queue.peek();
if (cmp(points[i], temp) > 0) {
queue.poll();
queue.add(points[i]);
}
}
}
int[][] res = new int[k][2];
for (int i = 0; i < k; i++)
res[i] = queue.poll();
return res;
}
int cmp(int[] a, int[] b) {
return (b[0] * b[0] + b[1] * b[1]) - (a[0] * a[0] + a[1] * a[1]);
}
题目:1630. 等差子数组
思路:暴力模拟
public List<Boolean> checkArithmeticSubarrays(int[] nums, int[] l, int[] r) {
List<Boolean> res = new ArrayList<>();
for (int i = 0; i < l.length; i++)
res.add(isArithmetic(Arrays.copyOfRange(nums, l[i], r[i] + 1)));
return res;
}
boolean isArithmetic(int[] arr) {
if (arr.length <= 1) return true;
Arrays.sort(arr);
int diff = arr[1] - arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] - arr[i - 1] != diff)
return false;
}
return true;
}
题目:429. N 叉树的层序遍历
let levelOrder = function (root: Node | null): number[][] {
if (!root) return []
let queue = [root], res = []
while (queue.length) {
let temp = []
for (let i = queue.length - 1; i >= 0; i--) {
let node = queue.pop()
temp.unshift(node.val)
queue.unshift(...node.children)
}
res.push(temp)
}
return res
};
题目:503. 下一个更大元素 II
暴力:
const nextGreaterElements = function (nums: number[]): number[] {
let len = nums.length
if (len <= 1) return [-1]
let res = new Array(len).fill(null)
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len + i; j++) {
if (nums[j % len] > nums[i]) {
res[i] = nums[j % len]
break
}
}
if (res[i] == null) res[i] = -1
}
return res
};
单调栈:
public int[] nextGreaterElements(int[] nums) {
int[] res = new int[nums.length];
Arrays.fill(res, -1);
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < nums.length * 2; i++) {
// 栈不为空, 且当前元素 > 栈顶下标对应的元素
while (!stack.isEmpty() && nums[i % nums.length] > nums[stack.getLast()]) {
// 更新栈顶下标对应的结果
res[stack.removeLast()] = nums[i % nums.length];
}
stack.addLast(i % nums.length);
}
return res;
}
题目:556. 下一个更大元素 III
此题和 31.下一个排列 几乎一样,加了一个返回值判断而已
思路:
对于 [2, 6, 3, 5, 4, 1]
先从后往前找到一个逆序数 N, 即为 3
然后再从 N 后面找到一个比它大的 “最小数”
即在 [5, 4, 1] 中找到比 3 大的最小数, 为 4
(这里可以直接再次从后往前找,因为这段数字倒着遍历必然是正序的)
交换两者位置,则为 [2, 6, 4, 5, 3, 1]
然后对一开始 N 后面位置进行反转
即从 [2, 6, 4, 5, 3, 1] 到 [2, 6, 4, 1, 3, 5]
public int nextGreaterElement(int n) {
char[] cs = String.valueOf(n).toCharArray();
int i = cs.length - 2;
// 从后往前找到第一个逆序的数字 N
while (i >= 0 && cs[i] >= cs[i + 1]) i--;
if (i < 0) return -1;
// 找到 N 后面比 N 大的 "最小数字"
int j = cs.length - 1;
while (j >= 0 && cs[j] <= cs[i]) j--;
// 交换 N 和 比N大的"最小数字"的位置
swap(cs, i, j);
// 将原来的 N 位置后面的数字变为最小序(本就是倒序,反转一下即可)
reverse(cs, i + 1);
// 转换成 int, 越界则返回 -1
long res = 0;
for (char c : cs) res = res * 10 + (c - '0');
return res > Integer.MAX_VALUE ? -1 : (int)res;
}
void reverse(char[] cs, int start) {
int i = start, j = cs.length - 1;
while (i < j) swap(cs, i++, j--);
}
void swap(char[] cs, int i, int j) {
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
以上是脚本宝典为你收集整理的《编程能力基础》刷题笔记 1 ~ 20 题全部内容,希望文章能够帮你解决《编程能力基础》刷题笔记 1 ~ 20 题所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。