丑数
LeetCode264题,寻找符合规定个数的数并返回。
思路分析:可以发现丑数属于2、3、5这三个数的倍数,并且不是丑数的数即便乘以2、3、5得到的数也不是丑数,所以丑数一定是丑数乘以2、3、5得到的,那么寻找第N个丑数,只需要转化为寻找第N个丑数是2、3、5之中的那个数,乘以几得到的数返回即可。
if (n <= 6) return n;
//存储丑数的数组
int[] uglyNum = new int[n];
uglyNum[0] = 1;
int m2 = 0, m3 = 0, m5 = 0;
for (int i = 1; i < n; i++) {
//三指针计算返回最小的数,并存储数组中
uglyNum[i] = Math.min(uglyNum[m2] * 2, Math.min(uglyNum[m3] * 3, uglyNum[m5] * 5));
//更新指针
if (uglyNum[m2] * 2 == uglyNum[i]) m2++;
if (uglyNum[m3] * 3 == uglyNum[i]) m3++;
if (uglyNum[m5] * 5 == uglyNum[i]) m5++;
}
return uglyNum[n - 1];
等差数列划分
给定一个数组,从该数组中找到符合等差数列的个数,需要注意的是找到的等差数列,也可以继续划分多个子等差数列,返回一共有多少个等差数列。
思路分析:迭代当前数组,比较当前数与下一个数的差是否等于下一个数与下下一个数的差,如果相等就继续往下判断,如果不等则计算当前已经找到的等差数列的个数。
public static int numberOfArithmeticSlices(int[] A) {
//小于3直接返回0
if (A.length < 3) {
return 0;
}
//计算有多少等差数组
int sum = 0;
for (int i = 0; i < A.length - 1; i++) {
//先求出一个差值
int sub = A[i + 1] - A[i];
//临时下标
int index = i + 1;
for (int j = i + 2; j < A.length; j++) {
//如果后面的数字和相邻的数差值不一致,则直接跳出循环
if (A[j] - A[index] != sub) {
break;
} else {
//否则记录当前数下标
index = j;
}
}
//k等于这次求出的子数组的长度,根据该长度计算这个子数组还可以分割为多少个等差数列
for (int k = index + 1 - i; k >= 3; k--) {
sum += k - 2;
}
//如果i+1=index则说明没有找到一个等差数列
if (i + 1 != index) {
//如果找到了,则直接从等差数列的最后一个数开始
i = index;
}
}
return sum;
}
寻找重复数
LeetCode287寻找重复数,给定一个数组,数组里面有一个重复数,该数可能重复多次,我们需要知道的是,如果一个有重复数的数组以他的值为下标进行游走时,一定会形成一个圈,最后会不断的循环。
思路分析:上述说了有重复数的数组会形成一个圈,而圈的入口就是我们要找的重复数,因为该值和下标的对应关系是多对一的,所以我们可以把这个题转化为寻找圈的入口点。
//声明两个快慢指针,fast走两步,slow走一步
int fast = nums[nums[0]];
int slow = nums[0];
while (fast != slow) {
fast = nums[nums[fast]];
slow = nums[slow];
}
//当第一个循环结束时,两个指针一定在圈内某处相遇,这时slow走了N步,fast走了2N步,如果设圈的周长为C,可以得出N%C==0;
//如果设起始点到圈的入口距离为NUM,则slow在圈的N-NUM处,所以当slow在走NUM步时必定在入口处,即重复点
fast = 0;
while (fast != slow) {
fast = nums[fast];
slow = nums[slow];
}
return fast;
接雨水
LeetCode407题,本质是求一个三维的高低不齐的模型,能接多少体积的雨水。
‘
思路分析:该题的难度较高,原因在于是一个三维的图像,很难把各个方面想清楚,况且存在多种情况,并不是简单的几个判断就能求出的,如可能存在当前墙的高度比周围墙的高度高,但是周围墙可蓄水,蓄水后当前墙是否也能够进行蓄水的问题。
该题采用深度优先的方法,从最外层往最里层蓄水,原因在于最外层的墙肯定是无法蓄水的,并且水是从高处往低处流的,先将外层墙壁都放入优先队列中,之后找到外层最低墙壁判断其四周是否有比其低的墙壁,如果有则该墙可以蓄水,将蓄水后的墙壁再次加入优先队列,不断的按照此操作完成解答。
class Point implements Comparable {
public int x, y, h;
public Point(int x, int y, int h) {
this.x = x;
this.y = y;
this.h = h;
}
@Override
public int compareTo(Object o) {
Point point = (Point) o;
return this.h - point.h;
}
}
public class Solution7 {
public static void main(String[] args) {
int[][] heightMap = {{12, 13, 1, 12},
{13, 4, 13, 12},
{13, 8, 10, 12},
{12, 13, 12, 12},
{13, 13, 13, 13}};
System.out.println(trapRainWater(heightMap));
}
public static int trapRainWater(int[][] heights) {
if (heights == null || heights.length == 0) {
return 0;
}
//高度优先队列,用于存储符合条件的墙壁
Queue<Point> queue = new PriorityQueue<>();
//记录已经在队列的墙
boolean[][] visited = new boolean[heights.length][heights[0].length];
//遍历最外围的墙壁
for (int i = 0; i < heights.length; i++) {
for (int j = 0; j < heights[i].length; j++) {
if (i == 0 || j == 0 || i == heights.length - 1 || j == heights[i].length - 1) {
queue.offer(new Point(i, j, heights[i][j]));
visited[i][j] = true;
}
}
}
//记录接雨量
int sum = 0;
//四个方向的数组
int[] dirs = {-1, 0, 1, 0, -1};
while (!queue.isEmpty()) {
//弹出当前高度最小的墙壁
Point temp = queue.poll();
//获取当前墙四周墙的高度
for (int i = 0; i < dirs.length - 1; i++) {
int x = temp.x + dirs[i];
int y = temp.y + dirs[i + 1];
if (x >= 0 && x < heights.length && y >= 0 && y < heights[0].length && !visited[x][y]) {
//判断该点的高度是否小于当前墙壁的高度
if (temp.h > heights[x][y]) {
//蓄水
sum += temp.h - heights[x][y];
}
//将当前墙壁四周的墙也加入优先队列
queue.offer(new Point(x, y, Math.max(heights[x][y], temp.h)));
visited[x][y] = true;
}
}
}
return sum;
}
}