弗洛伊德算法
查找多源最短路径
首先将数据放入二维数组中int[][] dp
然后两重循环遍历数组
最外层循环判断将该节点加入路径后的最短距离
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dp[i][j]>dp[i][k]+dp[k][j]){
dp[i][j]=dp[i][k]+dp[k][j];
}
}
}
}
注意无穷大的取值:不能让dp[i][k]+dp[k][j]大于int类型所取最大值,会出错
迪杰斯特拉算法
适合查找单源最短路径
同弗洛伊德算法,有一个二维数组int[][] dp
有一个int[] dist数组,记录目标节点到各节点的最短距离
有一个int[] book数组,记录当前节点是否被标记
最外层循环,是每次循环标记一个节点
第一个循环是找到未标记的距离目标节点最近的节点,进行标记
第二个循环是找到未标记的所有节点,在经历标记节点后,进行距离更新
int u=0;
for(int k=1;k<=n;k++){
u=-1;//记录下一个要标记的节点
for(int i=1;i<=n;i++){
if(!book[i]&&(u==-1||dist[i]>dist[u]){
u=i;
}
}
book[u]=true;//进行标记
for(int i=1;i<=n;i++){
if(!book[i]&&dist[i]>dist[u]+dp[u][i]){
dist[i]=dist[u]+dp[u][i];
}
}
}
并查集
朋友圈
首先需要一个记父节点的数组,切记当fa[i]==i时也就是节点父节点为本身时,即为根节点
首先有一个找根节点的过程
public int find(int x){
if(x==fa[x]){
return x;
}
else {
return fa[x]=find(fa[x]);//路径压缩
}
然后是合并的过程
需要一个秩组rank[]
public void merge(int i,intj){
int x=find(i),y=find(j);
if(rank[x]<=rank[y]){
fa[x]=y;
}
else{fa[y]=x;}
if(rank[x]==rank[y]&&x!=y)rank[y]++;
}
贪心算法
- Assign Cookies (Easy)
题目描述
有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个大小。每个孩子只能吃
最多一个饼干,且只有饼干的大小大于孩子的饥饿度时,这个孩子才能吃饱。求解最多有多少孩
子可以吃饱。
输入输出样例
输入两个数组,分别代表孩子的饥饿度和饼干的大小。输出最多有多少孩子可以吃饱的数
量。
Input: [1,2], [1,2,3]
Output: 2
题解:找到最饥饿度的孩子所对应的最小的饼干。
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g); //进行排序才能将最小满足的孩子与最小饼干匹配
Arrays.sort(s);
int i=0,j=0;
while(i<g.length&&j<s.length){//注意在这个地方只需要在饼干满足的情况下,计数孩子
if(s[j]>=g[i])i++;
j++;
}
return i;
}
链表
链表是最简单的线性的、动态数据结构。理解它是理解树结构、图结构的基础。
21.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
题解:
class Solution{
public ListNode mergeTwoLists(ListNode l1,ListNode l2){
ListNode next=new ListNode(0);
ListNode res=next;
while(l1!=null&&l2!=null){
if(l1.val<=l2.val){
next.next=new ListNode(l1.val);
l1=l1.next;
}else{
next.next=new ListNode(l2.val);
l2=l2.next;
}
next=next.next;
}
if(l1!=null)next.next=l1;
if(l2!=null)next.next=l2;
return res.next;
}
}
我自己的想法:利用归并排序,新建链表按顺序放置。
首先利用到了额外的空间,所以空间复杂度是O(n+m),时间复杂度是遍历两个链表所以也是O(n+m)
第一种方法:迭代
也就是我上面的这种方式,但是不是每一个结点都需要新建一个结点,只需要一个哨兵结点,记住链表的位置就行
class Solution{
public ListNode mergeTwoLists(ListNode l1,ListNode l2){
ListNode next=new ListNode(0);//哨兵结点
ListNode res=next;
while(l1!=null&&l2!=null){
if(l1.val<=l2.val){
next.next=l1;
l1=l1.next;
}else{
next.next=l2;
l2=l2.next;
}
next=next.next;
}
if(l1!=null)next.next=l1;
if(l2!=null)next.next=l2;
return res.next;
}
}
此时的空间复杂度为O(1)
第二种方法:递归
每次递归就决定下一个添加到结果里的结点。例如 l1.val<l2.val,那么第一个节点就是l1,需要return l1,并决定下一个节点的值是下一次递归的结果。
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null)return l2;
if(l2==null)return l1;
if(l1.val<l2.val){
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}else{
l2.next=mergeTwoLists(l2.next,l1);
return l2;
}
}
因为递归调用mergeTwoLists函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时mergeTwoLists函数最多被调用n+m次,因此空间复杂度O (n+m),时间复杂度O (n+m)
141.环形链表
给定一个链表,判断链表中是否有环。
题解:
第一种方法:利用快慢指针
public boolean hasCycle(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow)return true;
}
return false;
}
时间复杂度O(N),N为链表中的节点数
空间复杂度O(1),只额外使用了两个指针
第二种方法:利用哈希表
public boolean hasCycle(ListNode head) {
HashSet<ListNode> set=new HashSet<>();
while(head!=null){
if(!set.add(head)){
return true;
}
head=head.next;
}
return false;
}
时间复杂度O(N),空间复杂度O(N)
203.移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
第一种方法:迭代(利用哨兵节点)
public ListNode removeElements(ListNode head, int val) {
ListNode prehead=new ListNode();
ListNode pre=prehead;
prehead.next=head;
ListNode cur=head;
while(cur!=null){
if(cur.val==val){
pre.next=cur.next;
cur=pre.next;
}else{
pre=cur;
cur=cur.next;
}
}
return prehead.next;
}
第二种方法:递归(注意返回的是删除元素后的链表头节点,所以只需要判断当前节点是否需要删除.
public ListNode removeElements(ListNode head, int val) {
if(head==null)return null;
head.next=removeElements(head.next,val);
return head.val==val?head.next:head;
}
空间复杂度O(N),时间复杂度O(N)
705.设计哈希集合
class MyHashSet {
private static final int BASE = 769;
private LinkedList[] data;
/** Initialize your data structure here. */
public MyHashSet() {
data = new LinkedList[BASE];
for (int i = 0; i < BASE; ++i) {
data[i] = new LinkedList<Integer>();
}
}
public void add(int key) {
int h = hash(key);
Iterator<Integer> iterator = data[h].iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element == key) {
return;
}
}
data[h].offerLast(key);
}
public void remove(int key) {
int h = hash(key);
Iterator<Integer> iterator = data[h].iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element == key) {
data[h].remove(element);
return;
}
}
}
/** Returns true if this set contains the specified element */
public boolean contains(int key) {
int h = hash(key);
Iterator<Integer> iterator = data[h].iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element == key) {
return true;
}
}
return false;
}
private static int hash(int key) {
return key % BASE;
}
}