需要开通vip的题目暂时跳过
点击链接可跳转到所有刷题笔记的导航链接
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。
解答
class MyCircularQueue {
Node head;
Node tail;
public MyCircularQueue(int k) {
this.head = new Node(-1);
Node p = head;
k--;
while(k > 0){
p.next = new Node(-1);
p = p.next;
k--;
}
p.next = head;
tail = head;
}
public boolean enQueue(int value) {
if(tail.next == head)return false;
if(tail.val == -1){
tail.val = value;
return true;
}
tail = tail.next;
tail.val = value;
return true;
}
public boolean deQueue() {
if(head.val != -1){
if(head == tail){
head.val = -1;
}else{
head.val = -1;
head = head.next;
}
return true;
}
return false;
}
public int Front() {
return head.val;
}
public int Rear() {
return tail.val;
}
public boolean isEmpty() {
return head.val == -1;
}
public boolean isFull() {
return tail.next == head;
}
class Node{
int val;
Node next;
public Node(int val){
this.val = val;
}
}
}
分析
给定一个二叉树,根节点为第1层,深度为 1。在其第 d 层追加一行值为 v 的节点。
添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N,为 N 创建两个值为 v 的左子树和右子树。
将 N 原先的左子树,连接为新节点 v 的左子树;将 N 原先的右子树,连接为新节点 v 的右子树。
如果 d 的值为 1,深度 d - 1 不存在,则创建一个新的根节点 v,原先的整棵树将作为 v 的左子树。
解答
public TreeNode addOneRow(TreeNode root, int v, int d) {
List<TreeNode> list = new ArrayList<>();
list.add(root);
int depth = 1;
if(d == 1){
TreeNode h = new TreeNode(v);
h.left = root;
return h;
}
while(!list.isEmpty()){
List<TreeNode> temp = new ArrayList<>();
for(TreeNode node:list){
if(node.left != null){
temp.add(node.left);
}
if(node.right != null){
temp.add(node.right);
}
if(depth == d - 1){
TreeNode l = new TreeNode(v);
TreeNode r = new TreeNode(v);
l.left = node.left;
r.right = node.right;
node.left = l;
node.right = r;
}
}
list = temp;
depth++;
}
return root;
}
分析
给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
解答
//方法1
public int maximumProduct(int[] nums) {
Arrays.sort(nums);
int len = nums.length;
int num1 = nums[len-1] * nums[len-2] * nums[len-3];
int num2 = nums[0] * nums[1] * nums[len-1];
return Math.max(num1,num2);
}
//方法2
public int maximumProduct(int[] nums) {
if (nums.length < 3) {
return 0;
}
int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
for (int n : nums) {
if (n < min1) {
min2 = min1;
min1 = n;
} else if (n < min2) {
min2 = n;
}
if (n > max1) {
max3 = max2;
max2 = max1;
max1 = n;
} else if (n > max2) {
max3 = max2;
max2 = n;
} else if (n > max3) {
max3 = n;
}
}
return Math.max(min1 * min2 * max1, max1 * max2 * max3);
}
分析
提交结果
给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数。
逆序对的定义如下:对于数组的第i个和第 j个元素,如果满i < j且 a[i] > a[j],则其为一个逆序对;否则不是。
由于答案可能很大,只需要返回 答案 mod 109 + 7 的值。
解答
public int kInversePairs(int n, int k) {
int[][] dp = new int[n + 1][k + 1];
int M = 1000000007;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= k && j <= i * (i - 1) / 2; j++) {
if (i == 1 && j == 0) {
dp[i][j] = 1;
break;
} else if (j == 0)
dp[i][j] = 1;
else {
int val = (dp[i - 1][j] + M - ((j - i) >= 0 ? dp[i - 1][j - i] : 0)) % M;
dp[i][j] = (dp[i][j - 1] + val) % M;
}
}
}
return dp[n][k];
}
分析
这里有 n 门不同的在线课程,他们按从 1 到 n 编号。每一门课程有一定的持续上课时间(课程时间)t 以及关闭时间第 d 天。一门课要持续学习 t 天直到第 d 天时要完成,你将会从第 1 天开始。
给出 n 个在线课程用 (t, d) 对表示。你的任务是找出最多可以修几门课。
解答
public int scheduleCourse(int[][] courses) {
Arrays.sort(courses,(a,b)->{
return a[1] - b[1];
});
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>(){
public int compare(int[] o1,int[] o2){
return o2[0] - o1[0];
}
});
int time = 0;
for(int[] course:courses){
if(time + course[0] <= course[1]){
queue.offer(course);
time += course[0];
}else{
if(!queue.isEmpty() && queue.peek()[0] > course[0]){
time += course[0] - queue.poll()[0];
queue.offer(course);
}
}
}
return queue.size();
}
分析
你有 k 个 非递减排列 的整数列表。找到一个 最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。
解答
public int[] smallestRange(List<List<Integer>> nums) {
List<int[]> list = new ArrayList<>();
int k = nums.size();
for(int i = 0;i < k;i++){
List<Integer> l = nums.get(i);
for(int num : l){
list.add(new int[]{num,i});
}
}
Collections.sort(list, Comparator.comparingInt(o -> o[0]));
int[] res = new int[2];
int[] count = new int[k];
int temp = 0;
int j = 0;
for(int i = 0;i < list.size();i++){
if(count[list.get(i)[1]]++ == 0) temp++;
if(temp == k){
while(count[list.get(j)[1]] > 1)count[list.get(j++)[1]]--;
if((res[0] == 0 && res[1] == 0) || res[1] - res[0] > list.get(i)[0] - list.get(j)[0])
res = new int[]{list.get(j)[0],list.get(i)[0]};
}
}
return res;
}
分析
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。
解答
//方法1
public boolean judgeSquareSum(int c) {
for (long a = 0; a * a <= c; a++) {
double b = Math.sqrt(c - a * a);
if (b == (int) b)
return true;
}
return false;
}
//方法2
public boolean judgeSquareSum(int c) {
int left = 0;
int right = (int) Math.floor(Math.sqrt(c));
while(left <= right) {
int temp = left * left + right * right;
if(temp > c) {
right--;
}else if(temp < c) {
left++;
}else {
break;
}
}
if(left <= right) {
return true;
}else {
return false;
}
}
分析
提交结果
给出一个非抢占单线程CPU的 n 个函数运行日志,找到函数的独占时间。
每个函数都有一个唯一的 Id,从 0 到 n-1,函数可能会递归调用或者被其他函数调用。
日志是具有以下格式的字符串:function_id:start_or_end:timestamp。例如:“0:start:0” 表示函数 0 从 0 时刻开始运行。“00” 表示函数 0 在 0 时刻结束。
函数的独占时间定义是在该方法中花费的时间,调用其他函数花费的时间不算该函数的独占时间。你需要根据函数的 Id 有序地返回每个函数的独占时间。
解答
public int[] exclusiveTime(int n, List<String> logs) {
int[] res = new int[n];
Stack<String> stack = new Stack<>();
int lastTime = 0;
for(int i = 0;i < logs.size();i++){
String curLog = logs.get(i);
String[] curLogStrs = curLog.split(":");
if(stack.isEmpty()){
stack.push(curLog);
lastTime = Integer.valueOf(curLogStrs[2]);
continue;
}
if(curLogStrs[1].equals("end")){
String lastLog = stack.pop();
String[] lastLogStrs = lastLog.split(":");
res[Integer.valueOf(curLogStrs[0])] += Integer.valueOf(curLogStrs[2]) - lastTime + 1;
}else{
String lastLog = stack.peek();
String[] lastLogStrs = lastLog.split(":");
res[Integer.valueOf(lastLogStrs[0])] += Integer.valueOf(curLogStrs[2]) - lastTime -1;
stack.push(curLog);
}
lastTime = Integer.valueOf(curLogStrs[2]);
}
return res;
}
分析
解答
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
List<TreeNode> list = new ArrayList<>();
list.add(root);
while(!list.isEmpty()){
List<TreeNode> temp = new ArrayList<>();
double sum = 0;
int size = list.size();
for(TreeNode node:list){
sum += node.val;
if(node.left!=null)temp.add(node.left);
if(node.right!=null)temp.add(node.right);
}
res.add(sum/size);
list = temp;
}
return res;
}
分析
在LeetCode商店中, 有许多在售的物品。
然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。
现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单。请输出确切完成待购清单的最低花费。
每个大礼包的由一个数组中的一组数据描述,最后一个数字代表大礼包的价格,其他数字分别表示内含的其他种类物品的数量。
任意大礼包可无限次购买。
解答
int min = Integer.MAX_VALUE;
public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
dfs(price,special,needs,0,0);
return min;
}
public void dfs(List<Integer> price, List<List<Integer>> special, List<Integer> needs,int needMoney,int index){
for(int j = index;j < special.size();j++){
List<Integer> list = special.get(j);
List<Integer> remain = new ArrayList<>();
for(int i = 0;i < list.size()-1;i++){
if(list.get(i) > needs.get(i))break;
remain.add(needs.get(i) - list.get(i) >=0 ? needs.get(i) - list.get(i) : 0);
}
if(remain.size() == needs.size())
dfs(price,special,remain,needMoney + list.get(list.size()-1),j);
}
for(int i = 0;i < price.size();i++){
needMoney += needs.get(i) * price.get(i);
}
min = Math.min(min,needMoney);
}
分析
一条包含字母 A-Z 的消息通过以下的方式进行了编码:
除了上述的条件以外,现在加密字符串可以包含字符 '‘了,字符’'可以被当做1到9当中的任意一个数字。
给定一条包含数字和字符’*'的加密信息,请确定解码方法的总数。
同时,由于结果值可能会相当的大,所以你应当对109 + 7取模。(翻译者标注:此处取模主要是为了防止溢出)
解答
public int numDecodings(String s) {
int M = 1000000007;
long[] dp = new long[s.length() + 1];
dp[0] = 1;
dp[1] = s.charAt(0) == '*' ? 9 : s.charAt(0) == '0' ? 0 : 1;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == '*') {
dp[i + 1] = 9 * dp[i];
if (s.charAt(i - 1) == '1')
dp[i + 1] = (dp[i + 1] + 9 * dp[i - 1]) % M;
else if (s.charAt(i - 1) == '2')
dp[i + 1] = (dp[i + 1] + 6 * dp[i - 1]) % M;
else if (s.charAt(i - 1) == '*')
dp[i + 1] = (dp[i + 1] + 15 * dp[i - 1]) % M;
} else {
dp[i + 1] = s.charAt(i) != '0' ? dp[i] : 0;
if (s.charAt(i - 1) == '1')
dp[i + 1] = (dp[i + 1] + dp[i - 1]) % M;
else if (s.charAt(i - 1) == '2' && s.charAt(i) <= '6')
dp[i + 1] = (dp[i + 1] + dp[i - 1]) % M;
else if (s.charAt(i - 1) == '*')
dp[i + 1] = (dp[i + 1] + (s.charAt(i) <= '6' ? 2 : 1) * dp[i - 1]) % M;
}
}
return (int) dp[s.length()];
}
分析
动态规划
当前数字和前面得到的结果是有关联的。
初始条件dp[0] = 1,dp[1] = s.charAt(0) == ‘*’ ? 9 : s.charAt(0) == ‘0’ ? 0 : 1
从下标1开始遍历
若当前字符是"*" 那么dp[i + 1] = dp[i] * 9
若前一位是1 那么还要加上dp[i-1] * 9 表示 前i-1个字符 和后面两位字符 “1*” 的组合数
若前一位是2 那么还要加上dp[i-1] * 6 表示 前i-1个字符 和后面两位字符 “2*” 的组合数
若前一位是* 那么还要加上dp[i-1] * 15 表示 前i-1ge字符和后面两位字符 “**” 的组合数
若当前字符不是"*" 那么dp[i + 1] = s.charAt(i) != ‘0’ ? dp[i] : 0; 取决于当前字符是否是0
若前一位是1。那么还要加上dp[i-1] 表示 前i- 1个字符 和后面两位字符 "1x"的组合数
若前一位是2 并且当前位小于等于6 那么还要加上dp[i-1] 表示 前i-1个字符和后面两位 字符"2x"的组合数
若前一位是* 那么dp[i + 1] = (dp[i + 1] + (s.charAt(i) <= ‘6’ ? 2 : 1) * dp[i - 1]) % M;
最后返回dp数组中的最后一个数字
求解一个给定的方程,将x以字符串"x=#value"的形式返回。该方程仅包含’+’,’ - '操作,变量 x 和其对应系数。
如果方程没有解,请返回“No solution”。
如果方程有无限解,则返回“Infinite solutions”。
如果方程中只有一个解,要保证返回值 x 是一个整数。
解答
public String solveEquation(String equation) {
String[] strs = equation.split("=");
int leftNumber = 0,rightNumber = 0,leftXNumber = 0,rightXNumber = 0;
int num = 0;
int flag = 0;
int j = 0;
for(int i = 0;i < strs[0].length();i++){
char cur = strs[0].charAt(i);
if(cur >= '0' && cur <= '9'){
num = num * 10 + (cur - '0');
}else if(cur == 'x'){
if(num == 0){
if(i - 1 >= 0 && strs[0].charAt(i-1) == '0')continue;
num++;
}
flag = 1;
}else if(cur == '+' || cur == '-'){
if(j == 0){
if(flag == 1)leftXNumber += num;
else leftNumber += num;
}else{
if(flag == 1)leftXNumber -= num;
else leftNumber -= num;
}
flag = 0;
num = 0;
j = cur == '+' ? 0 : 1;
}
}
if(j == 0){
if(flag == 1)leftXNumber += num;
else leftNumber += num;
}else{
if(flag == 1)leftXNumber -= num;
else leftNumber -= num;
}
num = 0;
flag = 0;
j = 0;
for(int i = 0;i < strs[1].length();i++){
char cur = strs[1].charAt(i);
if(cur >= '0' && cur <= '9'){
num = num * 10 + (cur - '0');
}else if(cur == 'x'){
if(num == 0){
if(i - 1 >= 0 && strs[1].charAt(i-1) == '0')continue;
num++;
}
flag = 1;
}else if(cur == '+' || cur == '-'){
if(j == 0){
if(flag == 1)rightXNumber += num;
else rightNumber += num;
}else{
if(flag == 1)rightXNumber -= num;
else rightNumber -= num;
}
num = 0;
flag = 0;
j = cur == '+' ? 0 : 1;
}
}
if(j == 0){
if(flag == 1)rightXNumber += num;
else rightNumber += num;
}else{
if(flag == 1)rightXNumber -= num;
else rightNumber -= num;
}
int XNumber = leftXNumber - rightXNumber;
int Number = rightNumber - leftNumber;
if(XNumber == 0 && Number != 0)return "No solution";
else if(XNumber == 0 && Number == 0)return "Infinite solutions";
else if(XNumber != 0 && Number == 0)return "x=0";
else return "x=" + (Number / XNumber);
}
分析