leetcode刷题笔记(4)

主题:哈希表

(1)30. 串联所有单词的子串(错1)

一顿操作猛如虎,提交击败百分五;

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> res = new ArrayList<Integer>();
        Map<String,Integer> map = new HashMap<String,Integer>();
        for(String str : words){
            if(map.get(str) == null){
                map.put(str,1);
            }else{
                map.put(str,map.get(str)+1);
            }
        }
        int wlen = words[0].length();
        int len = s.length();
        for(int start= 0;start < len-wlen+1;start++){
            int left = start;
            int n = 0;
            while(left+wlen <= len && n < words.length){
                if(map.get(s.substring(left,left+wlen)) == null || map.get(s.substring(left,left+wlen)) == 0){
                    break;
                }else{
                    map.put(s.substring(left,left+wlen), map.get(s.substring(left,left+wlen))-1);
                    left += wlen;
                    n++;
                }
            }
            if(n == words.length){
                res.add(start);
            }
            map.clear();
            for(String str : words){
                if(map.get(str) == null){
                    map.put(str,1);
                }else{
                    map.put(str,map.get(str)+1);
                }
            }

        }
        return res;
    }
}

题解思路:使用temp_map和,map做比较,而不用每遍历一次重新生成map;双指针

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> res = new ArrayList<>();
        if (s == null || s.length() == 0 || words == null || words.length == 0) return res;
        HashMap<String, Integer> map = new HashMap<>();
        int one_word = words[0].length();
        int word_num = words.length;
        int all_len = one_word * word_num;
        for (String word : words) {
            map.put(word, map.getOrDefault(word, 0) + 1);
        }
        for (int i = 0; i < one_word; i++) {
            int left = i, right = i, count = 0;
            HashMap<String, Integer> tmp_map = new HashMap<>();
            while (right + one_word <= s.length()) {
                String w = s.substring(right, right + one_word);
                right += one_word;
                if (!map.containsKey(w)) {
                    count = 0;
                    left = right;
                    tmp_map.clear();
                } else {
                    tmp_map.put(w, tmp_map.getOrDefault(w, 0) + 1);
                    count++;
                    while (tmp_map.getOrDefault(w, 0) > map.getOrDefault(w, 0)) {
                        String t_w = s.substring(left, left + one_word);
                        count--;
                        tmp_map.put(t_w, tmp_map.getOrDefault(t_w, 0) - 1);
                        left += one_word;
                    }
                    if (count == word_num) res.add(left);
                }
            }
        }
        return res;
    }
}

(2)36. 有效的数独

我的思路:分别判断行、列、九宫格中的数字是否满足要求

class Solution {
    public boolean isValidSudoku(char[][] board) {
        for(int i = 0; i < 9; i++){
            if(!hang(board,i)){
                return false;
            }
            if(!lie(board,i)){
                return false;
            }
            if(!nine(board,i)){
                return false;
            }
        }
        return true;
    }

    public boolean hang(char[][] board, int row){
        HashSet set = new HashSet();
        for(int i = 0; i < 9;i++){
            if(board[row][i] == '.'){
                continue;
            }
            if(!set.contains(board[row][i])){
                set.add(board[row][i]);
            }else{
                return false;
            }
        }
        return true;
    }

    public boolean lie(char[][] board, int col){
        HashSet set = new HashSet();
        for(int i = 0; i < 9;i++){
            if(board[i][col] == '.'){
                continue;
            }
            if(!set.contains(board[i][col])){
                set.add(board[i][col]);
            }else{
                return false;
            }
        }
        return true;
    }

    public boolean nine(char[][] board, int index){
        HashSet set = new HashSet();
        int row = index / 3;
        int col = index % 3;
        for(int i = row*3 + 0; i < row*3+3;i++){
            for(int j = col*3+0; j < col*3+3;j++){
                if(board[i][j] == '.'){
                    continue;
                }
                if(!set.contains(board[i][j])){
                    set.add(board[i][j]);
                }else{
                    return false;
                }
            }
        }
        return true;
    }
}

题解思路:用三个哈希表分别记录行、列、小九宫格每个数字出现的次数

class Solution {
    public boolean isValidSudoku(char[][] board) {
        int[][] rows = new int[9][9];
        int[][] columns = new int[9][9];
        int[][][] subboxes = new int[3][3][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                char c = board[i][j];
                if (c != '.') {
                    int index = c - '0' - 1;
                    rows[i][index]++;
                    columns[j][index]++;
                    subboxes[i / 3][j / 3][index]++;
                    if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[i / 3][j / 3][index] > 1) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
}

(3)41. 缺失的第一个正数(错1)

题解思路:将负数变为n+1;将<=n的元素对应的位置变为负数;返回第一个大于0的下标+1;

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        for(int i = 0; i < n; i++){
            if(nums[i] <= 0){
                nums[i] = n + 1;
            }
        }
        for(int i = 0; i < n; i++){
            int num = Math.abs(nums[i]);
            if(num <= n){
                nums[num-1] = -Math.abs(nums[num-1]);
            }
        }
        for(int i = 0; i < n; i++){
            if(nums[i] > 0){
                return i+1;
            }
        }
        return n+1;
    }
}

(4)49. 字母异位词分组(错1)

方法1:排序

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        for (String str : strs) {
            char[] array = str.toCharArray();
            Arrays.sort(array);
            String key = new String(array);
            List<String> list = map.getOrDefault(key, new ArrayList<String>());
            list.add(str);
            map.put(key, list);
        }
        return new ArrayList<List<String>>(map.values());
    }
}

方法2:计数

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<String, List<String>> map = new HashMap<String, List<String>>();
        for(String str : strs){
            int[] temp = new int[26];
            String t = "";
            for(char c: str.toCharArray()){
                temp[c-'a']++;
            }
            for(int i = 0; i < temp.length; i++){
                t += (i+'a' + temp[i]); 
            }
            List<String> list = new ArrayList<String>();
            list = map.getOrDefault(t, list);
            list.add(str);
            map.put(t,list);
        }
        return new ArrayList<List<String>>(map.values());

    }
}

(5)73. 矩阵置零

我的思路:先遍历一遍矩阵,记录0元素所在行和列,再分别将行和列改为0;

class Solution {
    public void setZeroes(int[][] matrix) {
       boolean[] col = new boolean[matrix[0].length];
       boolean[] row = new boolean[matrix.length];
        for(int i = 0; i < matrix.length; i++){
            for(int j = 0; j < matrix[0].length; j++){
                if(matrix[i][j] == 0){
                    row[i] = true;
                    col[j] = true;
                }

            }
        }
        for(int i = 0; i < matrix.length; i++){
            if(row[i]){
                for(int j = 0; j < matrix[0].length; j++){
                    matrix[i][j] = 0;
                }
            }
        }
        for(int j = 0; j < matrix[0].length; j++){
            if(col[j]){
                for(int i = 0; i < matrix.length; i++){
                    matrix[i][j] = 0;
                }
            }
        }
    }
}

(6)146. LRU 缓存

python

class LRUCache:
    def __init__(self, capacity: int):
        self.count = capacity
        self.lis = []
        self.dic = {}
    def get(self, key: int) -> int:
        if key in self.dic:
            self.lis.remove(key)
            self.lis.append(key)
            return self.dic[key]
        else:
            return -1
    def put(self, key: int, value: int) -> None:
        if key in self.dic:
            self.dic[key] = value
            self.lis.remove(key)
            self.lis.append(key)
        else:
            if self.count == 0:
                self.lis.append(key)
                del self.dic[self.lis.pop(0)]
                self.dic[key] = value
            else:
                self.dic[key] = value
                self.lis.append(key)
                self.count -= 1

题解思路:哈希表+双向链表,使用hashmap存储key-value,同时使用双向链表管理key的出入

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;
        }else{
            moveToHead(node);
            return node.value;
        }
    }
    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if(node == null){
            DLinkedNode newNode = new DLinkedNode(key,value);
            cache.put(key,newNode);
            addToHead(newNode);
            size++;
            if(size > capacity){
                DLinkedNode tail = removeTail();
                cache.remove(tail.key);
                size--;
            }
        }else{
            node.value = value;
            moveToHead(node);
        }
    }
    private void addToHead(DLinkedNode node){
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }
    private void removeNode(DLinkedNode node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    private void moveToHead(DLinkedNode node){
        removeNode(node);
        addToHead(node);
    }
    private DLinkedNode removeTail(){
        DLinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }
}

(7)139. 单词拆分

错误思路:使用一个boolean变量标记是否可以拆分;用一个函数递归查找;当遇到很长的重复变量时,超出时间限制;
题解思路:动态规划,从开头由短至长检索子串是否可以拆分,去接与前长度为j的字符串是否可以拆分,以及后面这段字符是否在列表内;

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        int len = s.length();
        boolean[] dp = new boolean[len+1];
        dp[0] = true;
        for(int i = 0; i <= len; i++){
            for(int j = 0; j <= i; j++){
                if(dp[j] && wordDict.contains(s.substring(j,i))){
                    dp[i] = true;
                }
            }
        }
        return dp[len];
    }
}

(8)202. 快乐数

我的思路:使用一个列表记录前面出现过的数字,如果再次出现,说明进入死循环false。

class Solution {
    public boolean isHappy(int n) {
        if(n == 1){
            return true;
        }
        ArrayList<Integer> list = new ArrayList<Integer>();
        int temp = n;
        while(temp != 1){
            String s = (temp +"");
            int record = 0;
            for(int i = 0; i < s.length(); i++){
                record += (s.charAt(i)-'0')*(s.charAt(i)-'0');
            }
            temp = record;
            if(list.contains(temp)){
                return false;
            }
            list.add(temp);
        }
        return true;
    }
}

题解其他思路:快慢指针法;

(9)147. 对链表进行插入排序

我的思路:从前往后插入。先遍历一遍获得链表长度len,将执行len-1次插入,使用temp复制一个要插入的节点,将原来的节点删除,每次插入先移动到有序链表的前面,再进行比较,如果temp大于当前节点,且下一个节点不为null,后移,如果temp小于当前节点,将其插入该节点前,否则插入节点后。

class Solution {
    public ListNode insertionSortList(ListNode head) {
        if(head == null && head.next == null){
            return head;
        }              
        ListNode dummy = new ListNode(0,head);
        ListNode pre = dummy;
        ListNode cur = head;
        int len = 0;
        while(cur != null){
            cur = cur.next;
            len++;
        }
        for(int i = 0; i < len-1; i++){
            int moveCount = len-i-2;
            ListNode temp = new ListNode(dummy.next.val);
            dummy.next = dummy.next.next;
            pre = dummy;
            cur = dummy.next;
            while(moveCount > 0){
                pre = pre.next;
                cur = cur.next;
                moveCount--;
            }
            while(cur != null && cur.next != null && temp.val > cur.val){
                pre = pre.next;
                cur = cur.next;
            }
            if(temp.val <= cur.val){
                temp.next = cur;
                pre.next = temp;
            }else{
                cur.next = temp;
            }
             
        }
        return dummy.next;
    }
}

(10)106. 从中序与后序遍历序列构造二叉树(错1)

class Solution {
    int post_idx;
    int[] postorder;
    int[] inorder;
    Map<Integer,Integer> idx_map = new HashMap<Integer, Integer>();

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        this.inorder = inorder;
        this.postorder = postorder;
        post_idx = postorder.length-1;
        
        int idx = 0;
        for(Integer val: inorder){
            idx_map.put(val,idx++);
        }
        return findRoot(0,inorder.length-1);
    }
    public TreeNode findRoot(int in_left, int in_right){
        if(in_left > in_right){
            return null;
        }
        int root_val = postorder[post_idx];
        TreeNode root = new TreeNode(root_val);
        
        int index = idx_map.get(root_val);

        post_idx--;
        root.right = findRoot(index+1, in_right);
        root.left = findRoot(in_left, index-1);
        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值