【LeetCode】做一些题

1.两数之和

import java.util.HashMap;

class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(target - nums[i])) {
                return new int[]{map.get(target - nums[i]), i};
            } else {
                map.put(nums[i], i);
            }
        }
        return null;
    }
}


3.无重复字符的最长子串

import java.util.HashMap;

class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Character, Integer> map = new HashMap<>();
        int begin = 0;
        int maxLength = 0;
        for (int end = 0; end < s.length(); end++) {
            char c = s.charAt(end);
            if (map.containsKey(c)) {
                begin = Math.max(begin,map.get(c)+1);
                map.put(c, end);
            } else {
                map.put(c, end);
            }
            maxLength = Math.max(maxLength, s.substring(begin, end + 1).length());
        }
        return maxLength;
    }
}

要点:
1.用begin和end表示子串开始和结束位置
2.用hash表检查重复字符
3.从左向右查看每个字符,如果:
        没遇到重复字符,调整end
        遇到重复的字符,调整begin
        将当前字符放入hdsh表
4.end-begin+1是当前子串长度


20.有效的括号

class Solution {
    char[] array = new char[10000];
    int top = 0;

    public boolean push(char value) {
        if (isFull()) {
            return false;
        }
        array[top] = value;
        top++;
        return true;
    }

    public char pop() {
        char value = array[top - 1]; // 注意 pop 和 peek 时,top 要-1
        top--;
        return value;
    }

    public char peek() {
        char value = array[top - 1];
        return value;
    }

    public boolean isEmpty() {
        return top == 0;
    }

    public boolean isFull() {
        return top == array.length;
    }

    public boolean isValid(String s) {
        Solution stack = new Solution();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '(')
                stack.push(')');
            else if (c == '[')
                stack.push(']');
            else if (c == '{')
                stack.push('}');
            else {
                if (!stack.isEmpty() && c == stack.peek()) { // 注意 if 判断栈是否空
                    stack.pop();
                } else
                    return false;
            }
        }
        return stack.isEmpty(); // 最终栈空才是有效的括号,非空证明有多余的括号
    }
}

用栈处理,遇到左括号就把对应的右括号入栈

遇到右括号就 peek 栈顶元素,看看他们是否相同,如果相同,则证明这对括号有效,pop 弹出

如果不相同,就说明这对括号无效,有一对括号无效直接返回 false


21.合并两个有序链表

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode mergeList = new ListNode(-1, null);
        ListNode p1 = list1;
        ListNode p2 = list2;
        ListNode p = mergeList;

        while (p1 != null && p2 != null) {
            if (p1.val <= p2.val) {
                p.next = new ListNode(p1.val, p.next);
                p1 = p1.next;
            } else {
                p.next = new ListNode(p2.val, p.next);
                p2 = p2.next;
            }
            p = p.next;
        }
        if (p1 == null) {
            p.next = p2;
        } else {
            p.next = p1;
        }
        mergeList = mergeList.next;
        return mergeList;
    }
}

创建一个新链表 mergeList ,双指针,list1 list2 一个链表一个指针,小的元素放入新链表

来自哪个链表哪个指针向前走一步,当有一个指针为空,退出循环,把另一个表整体给新链表接上

最后链表要排掉最开始设置的哨兵 -1


83.删除排序链表中的重复元素

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode sentinel = new ListNode(Integer.MIN_VALUE, head);
        ListNode p1 = sentinel;
        ListNode p2 = head;
        while (p2 != null) {
            if (p1.val == p2.val) {
                p2 = p2.next;
                p1.next = p2;
                continue;
            }
            p2 = p2.next;
            p1 = p1.next;
        }
        return sentinel.next;
    }
}

带哨兵的单链表,双指针


136.只出现一次的数字

import java.util.HashSet;

class Solution {
    public int singleNumber(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (!set.add(nums[i])) {
                set.remove(nums[i]);
            }
        }
        return (int) set.toArray()[0];
    }
}

Q:为什么不用 HashMap ?

A:因为最后需要输出一个 int 整型,而 HashMap 最后转数组再转 int 很麻烦,而且占用空间也  大,用 HashSet 则很方便,而且 HashSet 不允许有重复的元素,非常适合


141.环形链表

public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode p1 = head;
        ListNode p2 = head;

        while (p2 != null && p2.next != null) {
            // if(p1 == p2)
            //     return true;
            // p1 = p1.next;
            // p2 = p2.next.next;

            p1 = p1.next;
            p2 = p2.next.next;
            if (p1 == p2)
                return true;
        }
        return false;
    }
}

【快慢指针】

如果快指针 p2 走完全程,说明 head 链表不是环形链表

如果两个快慢指针相遇,说明 head 链表是环形链表

注意要先走后判断,否则初始状态就是相遇状态


150.逆波兰表达式求值

【逆波兰表达式】(Reverse Polish Notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)

class Solution {
    private int[] array = new int[10000];
    private int top = 0; // 栈顶指针

    public boolean push(int value) {
        if (isFull()) {
            return false;
        }
        array[top] = value;
        top++;
        return true;
    }

    public int pop() {
        int value = array[top - 1]; // 注意 pop 和 peek 时,top 要-1
        top--;
        return value;
    }

    public int peek() {
        int value = array[top - 1];
        return value;
    }

    public boolean isEmpty() {
        return top == 0;
    }

    public boolean isFull() {
        return top == array.length;
    }

    public int evalRPN(String[] tokens) {
        char[] array = new char[10000]; // 自带的数组没用上
        int top = 0;

        Solution stack = new Solution();
        for (String t : tokens) {
            switch (t) {
                case "+" -> {
                    int a = stack.pop();
                    stack.push(stack.pop() + a);
                    break;
                }
                case "-" -> {
                    int a = stack.pop();
                    stack.push(stack.pop() - a);
                    break;
                }
                case "*" -> {
                    int a = stack.pop();
                    stack.push(stack.pop() * a);
                    break;
                }
                case "/" -> {
                    int a = stack.pop();
                    stack.push(stack.pop() / a);
                    break;
                }
                default -> {
                    stack.push(Integer.parseInt(t));
                    break;
                }
            }
        }
        return stack.pop();
    }
}

遇到数字就 Integer.parseInt 转换成 int 入栈

遇到运算符就出栈两个元素,再把运算结果入栈


 203.移除链表元素

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode sentinel = new ListNode(-1, head); // 哨兵
        ListNode prev = sentinel;
        ListNode curr = head;
        while (curr != null) {
            if (curr.val == val) {
                curr = curr.next;
                prev.next = curr;
                continue;
            }
            curr = curr.next;
            prev = prev.next;
        }
        return sentinel.next;
        // return head;
    }
}

利用带哨兵的单链表和双指针(prev 和 curr),依次遍历,当 curr 当前结点的值和 val 相等,则令 curr 指向下一个结点,并令 prev 指向 curr,把中间的结点跳过

但是如果最终 return 的是 head ,则不能通过 head = [7,7,7,7],val=7 用例(待解决)


206.反转链表

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode list = null;
        ListNode curr = head;
        while (curr != null) {
            list = new ListNode(curr.val, list);
            curr = curr.next;
        }
        return list;
    }
}

利用“头插法”( addFirst 方法)


217.存在重复元素

import java.util.HashMap;

class Solution {
    public boolean containsDuplicate(int[] nums) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i])) {
                return true;
            } else {
                map.put(nums[i], i);
            }
        }
        return false;
    }
}

不停把元素放进哈希表,如果重复就 return true,否则 false


819.最常见的单词

(p.s. 代码先放这里,实在是看不懂)

1.将 paragraph 截取为一个个单词

   用的是 split(string regex) 方法
2.将单词加入 map 集合,单词本身作为 key ,出现次数作为 valve ,避免禁用词加入
3.在map集合中找到 valve 最大的,返回它对应的 key 即可


234.回文链表

class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode p1 = head;
        ListNode p2 = head;

        while (p2 != null && p2.next != null) {
            p1 = p1.next;
            p2 = p2.next.next;
        }

        // ListNode headReverse = new ListNode(-1,null);
        ListNode headReverse = null;

        while (p1 != null) {
            // headReverse = new ListNode(p1.val, headReverse.next);
            headReverse = new ListNode(p1.val, headReverse);
            p1 = p1.next;
        }

        p1 = head;
        p2 = headReverse;
        while (p1 != null && p2 != null) {
            if (p1.val != p2.val) {
                return false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }
        return true;
    }
}

注释掉的代码为原来写的代码,不能通过用例[1,1,2,1],原因可能是 headReverse 链表中,初始了一个 val=-1 的结点,在与 head 链表比较的时候,会参与比较,从而输出 true

所以创建一个新链表的时候,直接初始为 null,后续循环指向自己,而不是 next 


876.链表的中间结点

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode p1 = head;
        ListNode p2 = head;

        while (p2 != null && p2.next != null) {
            p1 = p1.next;
            p2 = p2.next.next;
        }
        return p1;
    }
}

【快慢指针】

p1 慢指针 一次走一步

p2 快指针 一次走两步

这样 p2 为 null 的时候,p1 正好在中间

注意 while 循环判断的条件


  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值