Leetcode 刷题日记
2021.2.8
题目链接:
https://leetcode-cn.com/problems/number-of-students-unable-to-eat-lunch/submissions/
问题描述:
解答1:
根据题目进行模拟
代码:
import java.util.LinkedList;
class Solution {
public int countStudents(int[] students, int[] sandwiches) {
LinkedList<Integer> stu = new LinkedList<>();
LinkedList<Integer> san = new LinkedList<>();
for (int i = 0; i < students.length; i++) {
stu.addLast(students[i]);
san.addLast(sandwiches[i]);
}
int time = 0;
while(!san.isEmpty()){
if(time >= san.size()) return san.size();
else if(san.peek() == stu.peek()){
san.removeFirst();
stu.removeFirst();
time = 0;
}else if(san.peek() != stu.peek()) {
stu.addLast(stu.removeFirst());
time ++;
}
}
return 0;
}
}
分析:
时间复杂度:O(n)
空间复杂度:O(n)
运行结果:
评注:
这是完全根据题目要求进行模拟,所以运行效率不算很高。
值得注意的是,这里面调用了队列的size()方法,而该方法并不能算作是队列的基本方法。笔者目前还未找到不使用该方法的高效解答。
解答2:
对问题进行抽象简化
代码:
import java.util.LinkedList;
class Solution {
public int countStudents(int[] students, int[] sandwiches) {
int stu0 = 0;
//喜欢0的学生数量
int stu1 = 0;
//喜欢1的学生数量
for(int student : students){
if(student == 0) stu0++;
else if(student == 1) stu1++;
}
for(int sandwich : sandwiches){
if(sandwich == 0){
if(stu0 <= 0) return stu1;
//如果这个三明治是0,但是喜欢0的学生已经没有了,则之后的学生都吃不上午餐
else stu0--;
//若还有喜欢0的学生,则喜欢0的学生数量减1
}else if(sandwich == 1)
if(stu1 <= 0) return stu0;
else stu1 --;
//同理
}
return 0;
}
}
分析:
时间复杂度:O(n)
空间复杂度:O(n)
运行结果:
评注:
计算量(处理量)守恒原理
类比能量守恒定理,我们可以得到“计算量(处理量)守恒原理”。大脑对问题处理得多,计算机就处理得少,运行效率就高,反之运行效率就低。简单地说,如果你想让自己的代码更高效,就得开动脑筋,对问题进行抽象、简化,而不是简单地对题目进行模拟。这一原理在实际编程中处处都有体现,以下举两个例子:
1.递归的非递归化:递归可以提升代码的简洁性,这样大脑对问题的“处理”就少了,大部分工作都交给计算机完成,所以运行效率往往不高;但是在非递归化中,程序员必须模拟栈来储存变量,他要先在头脑中对问题进行抽象,这样代码的可读性下降,但程序运行效率却上升了。
2.算法实现:以KMP算法为例
在最开始学习一种算法时,我们往往从直观的角度去认识它,但若是想要实现这一算法,就不能简单地对头脑中的直观感受进行模拟,而是应该对其进行抽象,从而进行更优实现。
以下课程对KMP算法的讲解遵循了从感性到理性的过程,这也是算法实现的基本步骤。有兴趣可移步观看。
https://www.bilibili.com/video/BV1jb411V78H?from=search&seid=7065096747221127232