【leetcode刷题笔记(1)】


不要觉得每道题都有很巧妙的方法可以解出来,只是自己没想到;有思路就试着将其实现,尽可能写出来再看其他解法。

链表

(1)23.

(2)最长回文子串

我的思路:用一个方法判断字符串是否为回文字符串;主方法中,从长度为字符串的长度出发,判断是否为回文字符串,不是则长度减一,重新搜索。

class Solution {
    public String longestPalindrome(String s) {
        if(s.length() <= 1){
            return s;
        }
        for(int i = s.length(); i > 0; i--){
            for(int j = 0; j + i - 1 < s.length(); j++){
                if(palindrome(s.substring(j,j+i))){
                    return s.substring(j,j+i);
                }
            }
        }
        return s.substring(1);
    }
    public static boolean palindrome(String t){
        if(t.length() <= 1){
            return true;
        }
        int first = 0;
        int last = t.length() - 1;
        while(t.charAt(first) == t.charAt(last)){
            first++;
            last--;
            if(first >= last){
                return true;
            }
        }
        return false;
    }
}

法二:中心扩散法

class Solution {
    public String longestPalindrome(String s) {
        if(s.length() <= 1){
            return s;
        }
        int start = 0;
        int end = 0;
        int maxLen = 1;
        for(int i = 0;i < s.length()-1; i++){
            int len1 = entrySpread(s,i,i);
            int len2 = entrySpread(s,i,i+1);
            int len = len1 > len2 ? len1:len2;
            if(len > maxLen){
                start = i - (len-1)/2;
                end = i + len / 2;
                maxLen = len;
            }
        }
        return s.substring(start,end+1);

    }
    public static int entrySpread(String s,int left,int right){
        while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        return right - left - 1;  //注意边界
    }
}

法三:动态规划

class Solution {
    public String longestPalindrome(String s) {
        if(s.length() <= 1){
            return s;
        }
        boolean[][] dp = new boolean[s.length()][s.length()];
        for(int i = 0; i < s.length(); i++){
            dp[i][i] = true;
        }
        char[] charArray = s.toCharArray();

        for(int L = 2; L <= s.length(); L++){
            for(int i = 0; i + L <= s.length(); i++){
                int j = i + L - 1;
                if(charArray[i] != charArray[j]){
                    dp[i][j] = false;
                }else{
                    if(j - i < 3){
                        dp[i][j] = true;
                    }else{
                        dp[i][j] = dp[i+1][j-1];
                    }
                }
            }
        }
        int maxLen = 1;
        int start = 0;
        int end = 0;
        for(int i = 0; i < s.length();i++){
            for(int j = i; j < s.length();j++){
                if(dp[i][j] && j-i+1 > maxLen){
                    maxLen = j-i+1;
                    start = i;
                    end = j;
                }
            }
        }
        return s.substring(start,end+1);
    }
}

(3)25. K个一组翻转链表(错1)

递归

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null || k <= 1){
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        ListNode temp = null;
        ListNode first = cur;
        int canProceed = 0;
        int count = 0;
        while(canProceed < k && first != null){
            first = first.next;
            canProceed++;
        }

        if(canProceed == k){
            while(count < k && cur != null){
                temp = cur.next;
                cur.next = pre;
                pre = cur;
                cur = temp;
                count++;
            }
            if(temp != null){
                head.next = reverseKGroup(temp,k);
            }
            return pre;
        }else{
            return head;
        }

    }
}

(4)旋转链表

我的思路:遍历一边链表,记录链表长度,找到切割点,然后再遍历一遍,进行切割

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head == null || k == 0){
            return head;
        }
        int count = 0;
        ListNode cur = head;
        while(cur != null){
            count++;
            cur = cur.next;
        }
        k = k % count;
        int t = count - k;
        cur = head;
        for(int i = 0; i < t-1;i++){
            cur = cur.next;
        }
        ListNode temp = cur.next;
        cur.next = null;
        cur = temp;
        if(temp == null){
            return head;
        }
        while(temp.next != null){
            temp = temp.next;
        }
        temp.next = head;
        return cur;
    }
}

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

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode pre = head;
        ListNode cur = head.next;
        while(cur != null){
            if(pre.val == cur.val){
                pre.next = cur.next;
                cur = pre.next;
            }else{
                cur = cur.next;
                pre = pre.next;
            }
        }
        return head;
    }
}

(6)82. 删除排序链表中的重复元素 II

我的思路:创建一个不同值的头节点,如遇到重复值的节点,记录重复节点的值,往后找到与该值不同的节点为止,将pre.next指向这个节点。

小结:如果遇到不好处理的头节点,可以新建一个头节点。

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        head = new ListNode(head.val-1,head);
        ListNode pre = head;
        ListNode cur = head.next;
        while(cur != null && cur.next != null){
            if(cur.val == cur.next.val){
                int temp = cur.val;
                while(cur != null && cur.val == temp){
                    cur = cur.next;
                }
                pre.next = cur;
            }else{
                pre = pre.next;
                cur = cur.next;
            }
        }
        return head.next;
    }
}

(7)86. 分隔链表

我的思路:创建一个新链表,将值小于x的节点复制到新链表中,原来的链表删除掉这样的节点;然后将两条链表拼接。

class Solution {
    public ListNode partition(ListNode head, int x) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode newHead = new ListNode(x-1);
        ListNode newCur = newHead;
        head = new ListNode(x-1,head);
        ListNode pre = head;
        ListNode cur = head.next;
        while(cur != null){
            if(cur.val < x){
                newCur.next = new ListNode(cur.val);
                newCur = newCur.next;
                pre.next = cur.next;
                cur = pre.next;
            }else{
                pre = pre.next;
                cur = cur.next;
            }
        }
        newCur.next = head.next;
        return newHead.next;
    }
}

题解思路:创建两个链表分别记录小于x的节点,和其他节点,没有复制节点,然后将两个链表合并

class Solution {
    public ListNode partition(ListNode head, int x) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode small = new ListNode(x-1);
        ListNode smallHead = small;
        ListNode large = new ListNode(x-1);
        ListNode largeHead = large;
        while(head != null){
            if(head.val < x){
                small.next = head;
                small = small.next;
            }else{
                large.next = head;
                large = large.next;
            }
            head = head.next;
        }
        large.next = null; //避免成环
        small.next = largeHead.next;
        return smallHead.next;
    }
}

(8)92. 反转链表 II

我的思路:用新节点作为头节点,找到反转链表开始的位置,用一个空节点作为反转部分的头,反转len次之后,反转部分与后面的链表是分离的,将三部分链表拼接起来。

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        if(head == null || head.next == null || left == right){
            return head;
        }
        int len = right - left + 1;
        ListNode pre = new ListNode(0);
        ListNode newHead = pre;
        pre.next = head;
        ListNode cur = head;
        ListNode prepre = null;
        ListNode temp = null;
        for(int i = 0; i < left-1; i++){
            pre = pre.next;
            cur = cur.next;
        }
        while(len > 0){
            temp = cur.next;
            cur.next = prepre;
            prepre = cur;
            cur = temp;
            len--;
        }
        pre.next = prepre;
        while(prepre.next != null){
            prepre = prepre.next;
        }
        prepre.next = cur;
        return newHead.next;
    }
}

题解思路:一次遍历完成,穿针引线。

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        if(head == null || head.next == null || left == right){
            return head;
        }
        int len = right - left + 1;
        ListNode newHead = new ListNode(0);
        newHead.next = head;
        ListNode pre = newHead;
        ListNode cur = null;
        ListNode temp = null;
        for(int i = 0; i < left-1; i++){
            pre = pre.next;
        }
        cur = pre.next;
        for(int i = 0 ;i < right - left;i++){
            temp = cur.next;
            cur.next = temp.next;
            temp.next = pre.next;
            pre.next = temp;
        }
        return newHead.next;
    }
}

(9)109. 有序链表转换二叉搜索树(错1)

题解思路:快慢指针找到中间节点,作为根节点,递归构造平衡二叉树。

class Solution {
    public TreeNode sortedListToBST(ListNode head) {
        if(head == null){
            return null;
        }
        if(head.next == null){
            return new TreeNode(head.val);
        }
        ListNode pre = head;
        ListNode slow = pre.next;
        ListNode fast = slow.next;
        while(fast != null && fast.next != null){
            pre = pre.next;
            slow = pre.next;
            fast = fast.next.next;
        }
        
        TreeNode root = new TreeNode(slow.val);
        pre.next = null;
        slow = slow.next;
        root.left = sortedListToBST(head);
        root.right = sortedListToBST(slow);
        return root;
    }
}

(10)39. 组合总和(错1)

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        int len = candidates.length;
        if(len == 0){
            return res;
        }
        Arrays.sort(candidates);
        Deque<Integer> path = new ArrayDeque<>();
        drawBack(candidates, 0, len, target, path, res);
        return res;
    }

    public static void drawBack(int[] candidates, int begin, int len, int target,Deque<Integer> path,List<List<Integer>> res){
        if(target == 0){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i = begin;i < len; i++){
            if(target-candidates[i] < 0){
                break;
            }
            path.addLast(candidates[i]);
            drawBack(candidates, i, len, target-candidates[i], path, res);
            path.removeLast();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值