算法复习一【复杂度、数组、链表】

1、复杂度

常见的时间复杂度 :

O(1) ->HashMap
O(logn) -> 二叉树
O(n) -> for 循环
O(nlogn) -> for 循环嵌套二叉树
O(n2) -> for 循环嵌套for 循环

常见的空间复杂度

O(1) ->int number=1
O(n) -> int[n]
O(n^2) -> int[n][n]

2、数组

数组:插入因为插入需要将插入位置后面的数据往后挪,删除就是往前挪,寻找如果是按下标直接为O(1),如果按内容的话则平均为时间复杂度为O(n)

在这里插入图片描述

3、链表

可以由拥有值和下一个节点的Node对象去构成链表
在这里插入图片描述

LRU缓存算法的实现

在这里插入图片描述

双向链表

Node对象中需要多一个prev的节点指向上一个节点

如果建立在不查询的基础上,知道上一个节点,去删除/插入一个节点,单向链表的时间复杂度可以是O(1),但往往单向链表只知道下一个节点,所以加上查询,总的时间复杂度会是O(n)

而双向链表可以解决该问题,因为它可以知道上一个节点和下个节点,将上个节点和下个节点进行连接修改,插入/删除的时间复杂度会变为O(1);

在这里插入图片描述

翻转链表-1

题目:将单向链表进行翻转

思路:以三个为单位进行变化,首先第一个指向null,把第二个存起来,将第二个的next指向第一个,然后第三个存起来,将第三个的指向第二个,依次进行

public class ReverseLinkedList{
    public Node reverseLinkedList(Node node){
        if(node==null){
            return node;
        }
        //上一个节点
        Node prev=null;
        //当前节点
        Node cur=node;
        //下一个节点
        Node next=node.next;
        while(next!=null){
            cur.next=prev;
            prev=cur;
			cur=next;
            next=next.next;
        }
        cur.next=prev;
        return cur;
    }
}
public class Node{
    int value;
    Node next;
	public Node(int value){
		this.value=value;
	}
}
翻转链表-2

题目将第n和第m之间

思路:首先得把第n个Node和第m个Node取出来,还有nNode的上一个Node,mNode的下一个Node,取出来后再进行中间部分的翻转。

public class ReverseLinkedList{
    public Node reverseLinkedList(Node node,int m,int n){
        if(node==null || m>=n){
            return node;
        }
        //返回用的起始节点
        Node head=new Node(-1);
        head.next=node;
        //获取mNode和其前一个
        Node mNode=node;
        Node prevNode=head;
        for(int i=1;i<m;i++){
            prevNode=prevNode.next;
            mNode=mNode.next;
        }
        //获取nNode和其后一个
        Node nNode=node;
        Node postNode=node.next;
        for(int i=1;i<n;i++){
            nNode=nNode.next;
            postNode=postNode.next;
        }
        //用来调换顺序的数据
        Node cur=mNode.next;
        Node prev=mNode;
        Node next=cur.next;
		//最前和最后的指向调换
        prevNode.next=nNode;
        mNode.next=postNode;
		//进行中间顺序的调换
        for(int i=0;i<(n-m);i++){
            cur.next=prev;
            prev=cur;
            //此处不能用cur.next,因为在第一步就换成了prev
            cur=next;
            next=cur.next;
        }
        
        return head.next;
    }
}
深度拷贝带随机指针的链表

题目:其进行深拷贝
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RJx8a3xr-1646055152123)(C:\Users\76532\Desktop\面试复习\算法\深拷贝链表图.png)]

思路:该题有两只解法,①利用Map的结构区去进行深拷贝②利用链表的结构,由next结构进行拷贝插入,然后再一步一步分离开
在这里插入图片描述

1、利用Map结构
public class copyRandomList{

	public Node copyRandomList(Node head){
        if(head==null){
            return null;
        }
       	Map<Node,Node> map=new HashMap<>();
        Node nextNode=head;
        //复制所有节点
        while(nextNode!=null){
            Node copyNode=new Node(nextNode.val);
            map.put(nextNode,copyNode);
            nextNode=nextNode.next;
        }
        nextNode=head;
        //复制节点内容
        while(nextNode!=null){
            Node copyNode=map.get(nextNode);
            copyNode.next=map.get(nextNode.next);
            copyNode.random=map.get(nextNode.random);
            nextNode=nextNode.next;
        }
        return map.get(head);
    }
}

可以进行优化,只使用一个循环,将next和random遇到提前先创建好。

public class copyRandomList{
    public Node copyRandomList(Node head) {
      if(head==null){
            return null;
        }
        Map<Node,Node> map=new HashMap<>();
        Node nextNode=head;
        while(nextNode!=null){
            //先复制,看看存不存在,不存在则创建,存在则直接取出
            Node copyNode;
            if(!map.containsKey(nextNode)){
                copyNode=new Node(nextNode.val);
                map.put(nextNode,copyNode);
            }else{
                copyNode=map.get(nextNode);
            }
            //再看看存不存在next,不存在进行拷贝创建,然后赋予给copyNext
            if(map.containsKey(nextNode.next)){
               copyNode.next=map.get(nextNode.next);

            }else{
                 if(nextNode.next!=null){
                    Node nextCopy=new Node(nextNode.next.val);
                    map.put(nextNode.next,nextCopy);
                    copyNode.next=nextCopy;
                 }
            }
            //再看看存不存在random,不存在进行拷贝创建,然后赋予给copyNext
            if(map.containsKey(nextNode.random)){
                copyNode.random=map.get(nextNode.random);
            }else{
                if(nextNode.random!=null){
                     Node randomCopy=new Node(nextNode.random.val);
                    map.put(nextNode.random,randomCopy);
                    copyNode.random=randomCopy;
                }

            }
            nextNode=nextNode.next;
        }

        return map.get(head);
        }
    }
}
2、利用链表结构
public Node copyRandomList(Node head) {
 /**
 		 * 特殊情况
 		 */
 		if (head==null) {
 			return head;
 		}
 		/**
 		 * 本次拷贝分三个步骤
 		 * 1、拷贝对象
 		 * 2、赋予random
 		 * 3、最后赋予next
 		 */
 		CopyNode(head);
 		CopyRandom(head);
 		return CopyNext(head);
 	}
 	public void CopyNode(Node head){
 		/**
 		 * 该过程是把对象拷贝再插入
 		 */
 		Node next=null;
 		while(head!=null){
 			Node CopyNode =new Node(head.val);
 			next=head.next;
 			head.next=CopyNode;
 			CopyNode.next=next;
 			head=next;
 		}
 	}

 	public void CopyRandom(Node head){
 		/**
 		 * 先判断是否拥有随机对象
 		 * 将随机对象进行赋予
 		 */
 		Node CopyNode=null;
 		while(head!=null){
 			Node random=head.random;
            CopyNode= head.next;
	 		if (random!=null) {
	 			CopyNode.random=random.next;
	 		}
	 		head=CopyNode.next;
 		}


 	}

 	public Node CopyNext(Node head){
 		/**
 		 * 将其分开
 		 */
        Node NewHead=head.next;
 		Node CopyNext=null;
 		while(head!=null){
			CopyNext=head.next;
			head.next=CopyNext.next;
			head=head.next;
            if(CopyNext.next!=null){
                CopyNext.next=CopyNext.next.next;
            }
			
 		}
        return NewHead;
    }
两数相加

题目:两个链表中的数进行相加

思路:首先我们要考虑到当两个链表不一样长的情况,然后进位可以用一个对象存储,依次进行相加

img

 public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
     if(l1==null){
         return l2;
     }
     if(l2==null){
         return l1;
     }
     //存储进位
     int array=0;
     //建立存储结果的listNode
     ListNode sentry=new ListNode(-1);
     ListNode res=sentry;
     //存储和
     int sum=0;
     //存储余数
     int value=0;
     //都存在时
     while(l1!=null &&l2!=null){
         sum=l1.val+l2.val+array;
         value=sum%10;
         array=sum/10;
         sentry.next=new ListNode(value);
         sentry=sentry.next;
         l1=l1.next;
         l2=l2.next;
     }
     //只有l1存在时
      while(l1!=null){
         sum=l1.val+array;
         value=sum%10;
         array=sum/10;
         sentry.next=new ListNode(value);
         sentry=sentry.next;
         l1=l1.next;
     }
     //只有l2存在时
      while(l2!=null){
         sum=l2.val+array;
         value=sum%10;
         array=sum/10;
         sentry.next=new ListNode(value);
         sentry=sentry.next;
         l2=l2.next;
     }
     //都不存在时
     if (array!=0) {
			node=new ListNode(array);
			sentry.next=node;
	}
     return res.next;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值