题目描述1
笔者解答1.1
class Solution {
public int nthUglyNumber(int n) {
int count=1;
int num_result=1;
while(count<n){
num_result++;
int num=num_result;
boolean getone=false;
do
{
getone=false;
if(num%2==0){
num/=2;
getone=true;
}else if(num%3==0){
num/=3;
getone=true;
}else if(num%5==0){
num/=5;
getone=true;
}
}while(getone);
if(num==1)
count++;
}
return num_result;
}
}
笔者分析1.2
这是我最初的想法,时间超时了,当然很容易想到另一种方法。后面的数是前面某一个数的2,3,5倍。因为之前没用过堆,这里就当堆入门了,直接学习题解的方法。
算法:预计算1690个丑数:
初始化预计算用到的数组nums,堆heap和哈希表Seen跟踪在堆中出现过的元素,避免重复。
循环计算丑数:弹出堆中最小的数字k并添加到数组nums中。若2k.3k,5k不存在哈希表中,则将其添加到栈中并更新哈希表。
返回在数组中预先计算好的丑数。
class Ugly{
public int[] nums=new int[1690];
Ugly(){
HashSet<Long> seen=new HashSet();
PriorityQueue<Long> heap=new PriorityQueue<Long>();
seen.add(1L);
heap.add(1L);
long currUgly,newUgly;
int[] primes=new int[]{
2,3,5};
for(int i=0;i<1690;i++)
{
currUgly=heap.poll();
nums[i]=(int)currUgly;
for(int j:primes){
newUgly=currUgly*j;
if(!seen.contains(newUgly)){
seen.add(newUgly);
heap.add(newUgly);
}
}
}
}
}
class Solution{
public static Ugly u=new Ugly();
public int nthUglyNumber(int n){
return u.nums[n-1];
}
}
题目描述2
笔者分析2.1
giao了,这些简单题都写不来,这真的是用堆就可以解决的嘛,虽然思路很清晰,但实现起来太麻烦了,看到题解才发现,原来好多功能是可以直接调用库函数的呀。。。哭了。但话说回来,题解这个解法确实巧妙,用哈希表来记录每个单词出现次数,用优先级队列来实现单调堆,同时控制堆大小,明白了,之后的这些题会用到很多的数据结构。。。
class Solution {
public List<String> topKFrequent(String[] words, int k) {
Map<String,Integer> map=new HashMap<>(words.length);
//建立哈希表统计单词频率
for(String word:words){
map.put(word,map.getOrDefault(word,0)+1);
}
//小顶堆,相同频率下,字母顺序高的在前,方便入栈
PriorityQueue<String> queue=new PriorityQueue<>((o1,o2)->{
Integer o1Count=map.get(o1);
Integer o2Count=map.get(o2);
if(o1Count.equals(o2Count)){
return o2.compareTo(o1);
}else{
return o1Count-o2Count;
}
});
//维持topK频率的单词
for(String word:map.keySet()){
queue.offer(word);
if(queue.size()>k){
queue.poll();
}
}
LinkedList<String> stack=new LinkedList<>();
while(!queue.isEmpty()){
stack.push(queue.poll());
};
return stack;
}
}
题目描述3
笔者分析3.1
看完题目,感觉还行,但动不了手。。。直到看到题解,我人都傻了!下面的代码,如果不看注释,能看懂嘛(我把我能写的注释都写上去了。。)
class Solution {
Map<Integer, Integer> dist;//存储从出发点到该点的最短路径
public int networkDelayTime(int[][] times, int N, int K) {
Map<Integer, List<int[]>> graph = new HashMap();/*用于存储每个顶点及其下一个顶点的信息,顶点是Integer类型,该顶点和它下一个顶点的信息包含时间长,和两端点信息,所以是一个int[]型,就是times里面的一个元素。之所以还有一个List,那是因为该顶点可以走向的下一个顶点可能有多个*/
for (int[] edge: times) {
//每一条边都是int[]类型的,现在要将times中所有的边信息,结合拼成一张图并用graph保存
if (!graph.containsKey(edge[0]))//edge[0]是该边的起点
graph.put(edge[0], new ArrayList<int[]>());//如果该起点没有在图中,则新建并加入
graph.get(edge[0]).add(new int[]{
edge[1], edge[2]});//以该点为起点,加入边的信息(包括终点信息和边的长度)。
}
dist = new HashMap();
for (int node = 1; node <= N; ++node)
dist.put(node, Integer.MAX_VALUE);//初始化从出发点到每个点的最短路径
dist.put(K, 0);//出发点到自己本身的距离为0
boolean[] seen = new boolean[N+1];//标记该顶点是否已经走过
while (true) {
int candNode = -1;
int candDist = Integer.MAX_VALUE;
for (int i = 1; i <= N; ++i) {
if (!seen[i] && dist.get(i) < candDist) {
//如果该点没有走过,而且小于原来走的距离
candDist = dist.get(i);//记录该距离
candNode = i;//记录该点
}
}
if (candNode < 0) break;//如果所有点都走过,则跳出while
seen[candNode] = true;//标记该点已经走过
if (graph.containsKey(candNode))
for (int[] info: graph.get(candNode))//找出所有以该点为出发点的边
dist.put(info[0],
Math.min(dist.get(info[0]), dist.get(candNode) + info[1]));//更新从出发点到该点的最短距离
}
int ans = 0;
for (int cand: dist.values()) {
if (cand == Integer.MAX_VALUE) return -1;
ans = Math.max(ans, cand);//选出距离最长的那个输出
}
return ans;
}
}
题目描述4
笔者分析4.1
原来二分法也可以在图形中体现并运用出来,涨知识了。这种矩阵的题,我们虽然能归纳出:每个数字都大于它左上角的所有数字,小于右下角,其它象限大小不知。但我是真没想到可以用二分法做,哎。。。尽管告诉我是二分法,我也想不到可以这样使用,佩服,佩服!
class Solution {
public int kthSmallest(int[][] matrix, int k) {
int n = matrix.length;
int left = matrix[0][0];
int right = matrix[n - 1][n - 1];
while (left < right) {
int mid = ((right + left)/2);
if (check(matrix, mid, k, n)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
public boolean check(int[][] matrix, int mid, int k, int n) {
int i = n - 1;
int j = 0;
int num = 0;
while (i >= 0 && j < n) {
if (matrix[i][j] <= mid) {
num += i + 1;
j++;
} else {
i--;
}
}
return num >= k;
}
}
题目描述5
笔者解答5.1
class Solution {
public int[][] kClosest(int[][] points, int K) {
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<points.length;i++){
map.put(i,points[i][0]*points[i][0]+points[i][1]*points[i][1]);
}
PriorityQueue<Integer> queue=new PriorityQueue<>((o1,o2)->{
return map.get(o1)-map.get(o2);
});
for(int i=0;i<points.length;i++)
queue.offer(i);
int[][] str=new int[K][2];
int k=0;
while(k<K){
str[k]=points[queue.poll()];k++;
}
return str;
}
}
笔者分析5.2
总算是学以致用了一回,主要还是题目简单,用其他方法一样可以很快写出来,只不过这次用的是今天学的方法,强行装了波B。
总结
感觉堆题的难度和栈的题目不是一个层次的。。。。虽然开始写的几个题都很蒙,但之后也是适应了这些手法,并成功运用这些手法解决了一个简单题??!总之,收获颇丰,打击颇大!每日打卡第六天,以下图为证。