目录
142-环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:
你是否可以使用 O(1) 空间解决此题?
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null) return null;
ListNode fast = head, slow = head;
while(fast!=null&&fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast==slow) break;
}
if(fast ==null||fast.next==null) return null;
slow = head;
while(slow!=fast){
slow =slow.next;
fast = fast.next;
}
return fast;
}
}
146. LRU 缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
class LRUCache {
class DLinkedNode{
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
public DLinkedNode(){}
public DLinkedNode(int _key, int _value){
this.key = _key;
this.value = _value;
}
}
private Map<Integer,DLinkedNode> cache = new HashMap<Integer,DLinkedNode>();
private int size;
private int capacity;
private DLinkedNode head, tail;
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
DLinkedNode node = cache.get(key);
if(node == null) return -1;
moveTOHead(node);
return node.value;
}
//放入时候,先get,看是否数据已经存在,如果已经存在则把它移动到链表头部
//不存在则创建新的节点,放在链表开头,并添加到hash表中,然后查看是否容量超过设置大小,超过则删除尾结点(最久 不使用)
public void put(int key, int value) {
DLinkedNode node = cache.get(key);
if(node==null){
DLinkedNode curNode = new DLinkedNode(key,value);
// 添加进哈希表
cache.put(key,curNode);
//添加到头部
addToHead(curNode);
++size;
if(size>capacity){
// 如果超出容量,删除双向链表的尾部节点,即tail节点的前一个节点
DLinkedNode tail = removeTail();
//删除哈希表中对应的项
cache.remove(tail.key);
--size;
}
}else{
//存在,则移动到头部
node.value = value;
moveTOHead(node);
}
}
//将最近使用节点,移动到双向链表头部
//先把原来的点删除,然后新增到头部
private void moveTOHead(DLinkedNode node){
removeNode(node);
addToHead(node);
}
//双向链表中删除节点
private void removeNode(DLinkedNode node){
node.prev.next = node.next;
node.next.prev = node.prev;
}
//添加到头部
private void addToHead(DLinkedNode node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
//删除结尾
private DLinkedNode removeTail() {
DLinkedNode res = tail.prev;
removeNode(res);
return res;
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
148-排序链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode slow = head,fast = head;
//寻找中间节点
while(fast.next!=null&&fast.next.next!=null){
slow = slow.next;
fast = fast.next.next;
}
//链表第二部分的头节点
ListNode rightHead = slow.next;
//把链表切开,分成两部分
slow.next = null;
return merge(sortList(head), sortList(rightHead));
}
//两个链表合并
private ListNode merge(ListNode head1, ListNode head2) {
ListNode pre = new ListNode(0);
ListNode temp = pre, temp1 = head1, temp2 = head2;
while(temp1!=null&&temp2!=null){
if(temp1.val<=temp2.val){
temp.next = temp1;
temp1 = temp1.next;
}else{
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
temp.next = temp1 == null ? temp2 :temp1;
return pre.next;
}
}
152-乘积最大子数组
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
class Solution {
/**
标签:动态规划
遍历数组时计算当前最大值,不断更新
令imax为当前最大值,则当前最大值为 imax = max(imax * nums[i], nums[i])
由于存在负数,那么会导致最大的变最小的,最小的变最大的。
因此还需要维护当前最小值imin,imin = min(imin * nums[i], nums[i])
当负数出现时则imax与imin进行交换再进行下一步计算
时间复杂度:O(n)O(n)
*/
public int maxProduct(int[] nums) {
int max=Integer.MIN_VALUE;//结果最大值
int imax=1;int imin=1;//阶段最大值 阶段最小值
for(int tmp:nums)
{
//当遇到负数的时候进行交换,因为阶段最小*负数就变阶段最大了,反之同理
if(tmp<0){
int exc=imax;
imax=imin;
imin=exc;
}
//在这里用乘积和元素本身比较的意思是:
//对于最小值来说,最小值是本身则说明这个元素值比前面连续子数组的最小值还小。相当于重置了阶段最小值的起始位置
imax=Math.max(imax*tmp,tmp);
imin=Math.min(imin*tmp,tmp);
//对比阶段最大值和结果最大值
max=Math.max(imax,max);
}
return max;
}
}
155-最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
示例:
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]输出:
[null,null,null,null,-3,null,0,-2]解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
class MinStack {
/** initialize your data structure here. */
Deque<Integer> stack;
Deque<Integer> minStack;
public MinStack() {
stack = new LinkedList<>();
minStack = new LinkedList<>();
}
//进栈的时候判断,是否要将值进入最小栈
public void push(int val) {
stack.push(val);
if(minStack.isEmpty()){
minStack.push(val);
//等号也要入栈
} else if(minStack.peek()>=val){
minStack.push(val);
}
}
//出栈判断当前最小栈栈顶元素是不是原栈顶元素
public void pop() {
//注意!!!比较应该equals
if(stack.pop().equals(minStack.peek()))
minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}