LeetCode刷题记录
2021.01.04-斐波那契数列
题目:计算斐波那契数列
题目分析:如果直接使用递归,时间复杂度O(2^n),会爆;观察使用递归时间复杂度这么高的原因主要是递归树结点的重复计算,可以考虑将中间结果存入到HashMap集合中,在递归计算前先查看下集合中有没有数据,如果已经有的话则无需递归计算
也可以使用动态规划的思想,要求的值为从开头,前两个相加得到结果,在和第二个值相加…不断向后移动知道要求的值的那一位,可以设first=0,second=0,temp=1然后从2开始,一直到目标值,使用
first = second;
second = temp;
temp = first + second;
public int fib(int n) {
/**
* 递归 O(2^n)
* f(n) = f(n-1) + f(n-2)
* */
// if (n == 0 || n == 1) {
// return n;
// }
// return fib(n-1) + fib(n-2);
/**
* 非递归,动态规划
* 从first开始逐步加,发现规律first为f(n)
*/
// int first = 0;
// int second = 1;
// // 记得初始化
// int temp = 0;
// for (int i=n; i>0; i--) {
// temp = first + second;
// first = second;
// second = temp;
// }
// return first;
// 或者
// if (n < 2) {
// return n;
// }
// int p = 0, q = 0, r = 1;
// for (int i = 2; i <= n; ++i) {
// p = q;
// q = r;
// r = p + q;
// }
// return r;
// 将中间结果保存
return fib(n,new HashMap<>());
}
// 集合对象中元素类型为包装类型
private int fib(int n, HashMap<Integer,Integer> map) {
if (n < 2) {
return n;
}
if (map.containsKey(n)) {
return map.get(n);
}
int first = fib(n-1,map);
int second = fib(n-2,map);
int result = (first + second);
// 将新算的值存入到map中
map.put(n,result);
return result;
}
2021.01.05-较大分组的位置
题目:解析字符串,输出连续字符的下标集合
解析:使用双指针法,通过移动right指针,比对right和left对应的元素是否相同,如果相同则计数。不同的时候判断计数是否大于等于3,如果是则创建一个当前left和right下标为集合,然后存入到较大分组集合中,同时计数清零。移动left指针到right,重新移动right进行判断
/**
* 较大分组的位置
* 先遍历字符串找到较大分组,然后插入到List集合中输出
* 寻找的方法:双指针法,移动right和left比较,不相同的话移动left=right,相同的话right++,
* 不相同之后查看count值为多少,如果大于等于3,则构造一个List集合存入此时的left和right值(然后再left=right,right++)
*/
public class LargeGroupPositions {
public List<List<Integer>> largeGroupPositions(String s) {
// 定义存储所有较大分组的集合
List<List<Integer>> largeGroup = new ArrayList<>();
// // 将字符串转为字符数组 不需要转换为字符数组,数组需要提前分配空间占用内存,消耗资源,直接使用字符串的charAt方法获取元素即可
// char[] strings = s.toCharArray();
// 定义左右指针
int left = 0;
int right = 1;
// 定义计数器
int count = 1;
for (;right<s.length();) {
if (s.charAt(left) != s.charAt(right)) {
if (count >= 3) {
// 定义存储left和right的list集合
// List<Integer> largeParam = new ArrayList<>();
// largeParam.add(left);
// largeParam.add(right-1);
// largeGroup.add(largeParam);
// 相比较使用创建一个新的List集合存储left和right,使用Arrays的asList(Object o)方法节省内存(常用接口需要熟记)
largeGroup.add(Arrays.asList(left,right-1));
}
left = right;
// count归零
count = 1;
} else {
count++;
}
if (right == s.length()-1){
if (count >= 3) {
// 定义存储left和right的list集合
// List<Integer> largeParam = new ArrayList<>();
// largeParam.add(left);
// largeParam.add(right);
largeGroup.add(Arrays.asList(left,right));
// largeGroup.add(largeParam);
// count归零
count = 1;
}
}
right++;
}
return largeGroup;
}
public static void main(String[] args) {
LargeGroupPositions largeGroupPositions = new LargeGroupPositions();
System.out.println(largeGroupPositions.largeGroupPositions("bababbabaa"));
// System.out.println("abbxxxxzzy".charAt(0));
}
}
题解二:一次遍历,结合count和left
停止计数的条件:
1,遇到不相同的
2,字符串遍历结束(勿忘)
int n = s.length();
int count = 1;
// 多次使用s.length(),则将其赋值给变量n;而非每次都重新计算
for (int i = 0; i < n; i++) {
if (i == n - 1 || s.charAt(i) != s.charAt(i + 1)) {
if (count >= 3) {
// 下标注意需要+1
largeGroup.add(Arrays.asList(i - count + 1, i));
}
// 计数器归零
count = 1;
} else {
count++;
}
}
return largeGroup;
2021.01.07-省份数量547
题目:给一个矩阵(二维数组),构造成一个图。遍历结点获取连通图并进行计数
解题思路:很容易想到图的深度遍历算法,构造一个已遍历的数组,初始化数组元素值为0,表示未开始遍历图
遍历数组,当元素为0的时候开始从下标开始,对图进行深度遍历,遍历结束即构造了一个连通路线,将省份树+1
深度遍历中,主要对二维数组规定i值,对j值进行遍历,当ij对应的值为1且此时i对应的已遍历数组中值为0(即此结点未遍历到),则递归
时间复杂度:O(n^2) 需要遍历矩阵(二维数组)
空间复杂度:O(n) 用数组visited记录每个城市是否被访问过
class Solution {
public int findCircleNum(int[][] isConnected) {
// 深度优先算法DFS
// 定义一个一维数组存储已经遍历到的结点
int count = 0;
int[] visited = new int[isConnected.length];
// 初始化
for (int i = 0; i < visited.length; i++) {
visited[i] = 0;
}
// 遍历查看现在是否有未遍历过的节点
for (int i = 0; i < visited.length; i++) {
if (visited[i] == 0) {
count++;
DFS(i, visited, isConnected);
}
}
return count;
}
private void DFS(int v, int[] visited, int[][] isConnected) {
// 遍历结点集合,从第一个结点开始,遍历isConnected(横向遍历),找到第一个值为1的点获取列索引,
// 然后递归遍历,直到结果为0,将中间遍历到的结点存入到已遍历集合中,并计数++(省份数量)
v