LeetCode Top100之142,146,148,152,200题

142. 环形链表 II
① 题目描述

中文题目:https://leetcode-cn.com/problems/linked-list-cycle-ii/

② 使用HashMap
  • 使用HashMap存储所有的非空结点,如果发现结点已经存在,便返回该结点。
  • 代码如下,运行时间8ms
public ListNode detectCycle(ListNode head) {
    HashMap<ListNode, Integer> map = new HashMap<>();
    while (head != null) {
        if (map.containsKey(head)) {
            return head;
        }
        map.put(head, 1);
        head = head.next;
    }
    return null;
}
③ 快慢指针(不行!只能判断是否有环)
  • 之前在环形链表中,使用了快慢指针,于是想使用快慢指针,发现不可以!快慢指针只能判断是否存在环。
  • head = [3,2,0,-4], pos = 1为例,发现在结点0处,slow和fast指针发生相遇,并非在结点2处相遇!
    在这里插入图片描述
  • 代码如下:
public ListNode detectCycle(ListNode head) {
    if (head == null) {
        return null;
    }
    ListNode slow = head, fast = head.next;
    while (slow != fast) {
        if (fast == null || fast.next == null) {
            return null;
        }
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
}
146. LRU缓存机制
① 题目描述

中文题目:https://leetcode-cn.com/problems/lru-cache/

② 自己的想法(使用List+哈希表)
  • 使用List数组作为缓存,最近使用的放到index = 0的位置,最近最少使用的放到尾部。
  • 将key和value设计为Node类,List中存放node对象。
  • 使用哈希表存储对应的结点,方便get时实现线性查找。
  • get时,若结点不在哈希表中,肯定不在List中,直接返回-1;如果结点在哈希表中,需要返回实际的只,并更新List中对应结点的热度(将他从原始的位置删除,然后在头部添加);
  • put时,若结点在哈希表中,需要更新List中对应结点的value并将其放置到头部;如果不在哈希表中,而此时缓存已满,则需要删除List末尾的结点和哈希表中对应的结点,并将新节点加入到List和哈希表中;否则,直接在List头部添加结点,并在哈希表中添加结点。
  • 哈希表和List有着相辅相承的作用。
  • 代码如下,运行时间240ms
class Node {
    public int key;
    public int value;
    public Node(int key, int value) {
        this.key = key;
        this.value = value;
    }
}

public class LRUCache {
    private List<Node> cache;
    private HashMap<Integer, Node> map;
    private int capacity;
    public LRUCache(int capacity) {
        cache = new ArrayList<>();// index=0,表示最近被访问的结点;尾部表示最近最少使用的结点
        map = new HashMap<>();
        this.capacity = capacity;
    }
    public int get(int key) {
        if (map.containsKey(key)) {// 结点已经存在,更新cache中的热度
            Node node = map.get(key);
            deleteNode(node.key, node.value);// 先删除对应的结点,再在头部添加新结点
            cache.add(0, new Node(node.key, node.value));
            return node.value;
        }
        return -1;// 结点不存在,返回-1
    }
    public void put(int key, int value) {
        if (map.containsKey(key)) {// 该节点已经存在,删除cache中已经存在的结点,为更新热度和值做准备
            Node node = map.get(key);
            deleteNode(node.key, node.value);
        } else if (cache.size() == capacity) {// 结点不存在,但是已经超过容量,删除cache和哈希中的最后一个结点
            Node node = cache.get(capacity - 1);
            cache.remove(capacity - 1);
            map.remove(node.key);
        }
        map.put(key, new Node(key, value));// 更新哈希表和cache
        cache.add(0, new Node(key, value));
    }

    public void deleteNode(int key, int value) {
        for (int i = 0; i < cache.size(); i++) {
            if (cache.get(i).key == key && cache.get(i).value == value) {
                cache.remove(i);
                break;
            }
        }
    }
}
148. 排序链表
① 题目描述

中文题目:https://leetcode-cn.com/problems/sort-list/

② 自己的想法:借助List
  • 第一次遍历,获取链表结点的值存入List中;对List排序后,第二次遍历,更改每个结点的值。
  • 时间复杂度: O ( 3 n ) O(3n) O(3n),更改结点值的同时需要遍历List;空间复杂度 O ( n ) O(n) O(n)
  • 代码如下,运行时间13ms
public ListNode sortList(ListNode head) {
    if (head == null) {
        return head;
    }
    List<Integer> list = new ArrayList<>();
    ListNode p = head;
    while (p != null) {
        list.add(p.val);
        p = p.next;
    }
    Collections.sort(list);
    p = head;
    int i = 0;
    while (p != null) {
        p.val = list.get(i++);
        p = p.next;
    }
    return head;
}
152. 乘积最大子序列
① 题目描述

中文题目:https://leetcode-cn.com/problems/maximum-product-subarray/

② 暴力法
  • 直接上代码,运行时间86ms
public int maxProduct(int[] nums) {
    int result = Integer.MIN_VALUE;
    for (int i = 0; i < nums.length; i++) {
        int temp = 1;
        for (int j = i; j < nums.length; j++) {
            temp = temp * nums[j];
            if (temp > result) {
                result = temp;
            }
        }
    }
    return result;
}
200. 岛屿数量
① 题目描述

中文题目:https://leetcode-cn.com/problems/number-of-islands/

② DFS
  • 发现基于矩阵的搜索,基本都是用dfs,而且需要借助visited数组,避免重复访问。
  • 把每个字符为1的位置,都视为一种可能的岛屿的起始点,不断向周围扩展,直到访问至边界。
  • 访问的方向一般都是:上、下、左、右。
  • 停止访问的条件是:i < 0 || i >= row || j < 0 || j >= col
  • 代码如下,运行时间1ms
public int numIslands(char[][] grid) {
    if (grid.length==0||grid[0].length==0){
        return 0;
    }
    int result = 0;
    boolean[][] visited = new boolean[grid.length][grid[0].length];
    for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[0].length; j++) {
            if (!visited[i][j] && grid[i][j] == '1') {
                result++;
                dfs(grid, i, j, visited);
            }
        }
    }
    return result;
}

public void dfs(char[][] grid, int i, int j, boolean[][] visited) {
    if (i >= 0 && i < grid.length && j >= 0 && j < grid[0].length// 行、列合法
            && !visited[i][j] && grid[i][j] == '1') {// 未被访问,是陆地
        visited[i][j]=true;// 标记为被访问过
        dfs(grid, i, j - 1, visited);// 左边位置
        dfs(grid, i, j + 1, visited);// 右边位置
        dfs(grid, i - 1, j, visited);// 上方位置
        dfs(grid, i + 1, j, visited);// 下方位置
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值