秋招打卡018(0831)


前言

提示:这里为每天自己的学习内容心情总结;

Learn By Doing,Now or Never,Writing is organized thinking.

刷题 and 面经。

先多,后少。


提示:以下是本篇文章正文内容

一、今天学习了什么?

  • 贪心算法;
  • 数组,代码随想录;
  • 链表,代码随想录;

二、关于问题的答案

1、贪心

    public int canCompleteCircuit(int[] gas, int[] cost) {
        /**
         * curGas:当前有的油量
         * totalGas:全部绕完需要的油量
         */
        int curGas = 0;
        int totalGas = 0;
        int index = 0;// 记录开始顺序绕环路的下标
        for (int i = 0; i < gas.length; i++) {
            curGas += gas[i] - cost[i];
            totalGas += gas[i] - cost[i];
            if (curGas < 0) {
                // 如果当前剩余的油量为负数,那么就代表失败
                curGas = 0;
                index = (i + 1) % gas.length;
            }
        }

        // 最后判断
        if (totalGas < 0) {
            return -1;
        }
        return index;
    }
    public int candy(int[] ratings) {
        /**
         * - dp[i],代表第i个下标的孩子,需要的最少糖果数目
         * - 贪心策略是,遍历两次
         *  - 从左朝右遍历时,只要右边的孩子评分比左边孩子大,就需要多给一个
         *  - 从右朝左遍历时,只要左边的孩子评分比右边孩子大,就需要多给一个
         */
        int length = ratings.length;
        int[] dp = new int[length];
        dp[0] = 1;

        for (int i = 1; i < length; i++) {
            dp[i] = ratings[i] > ratings[i - 1] ? dp[i - 1] + 1 : 1;
        }

        for (int i = length - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) {
                dp[i] = Math.max(dp[i], dp[i + 1] + 1);// 很重要
            }
        }

        int sum = 0;
        for (int i = 0; i < length; i++) {
            sum += dp[i];
        }

        return sum;
    }
    public boolean lemonadeChange(int[] bills) {
        /**
         * - five:当前手上有五美元钞票的张数
         * - ten:当前手上有10美元钞票的张数
         */
        int five = 0;
        int ten = 0;
        for (int i = 0; i < bills.length; i++) {
            if (bills[i] == 5) {
                five++;
            } else if (bills[i] == 10) {
                five--;
                ten++;
            } else {
                if (ten > 0) {
                    ten--;
                    five--;
                } else {
                    five -= 3;
                }
            }
            if (five < 0 || ten < 0) {
                return false;
            }
        }
        return true;
    }
    public int[][] reconstructQueue(int[][] people) {
        /**
         * - 首先根据people[i][0]进行降序排序,两个相同时按照第二个元素大小进行升序排序
         */
        Arrays.sort(people, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] - o2[0] == 0 ? o1[1] - o2[1] : o2[0] - o1[0];
            }
        });

        /**
         * 从左到右遍历数组元素,将元素放入队列中,按照顺序
         */
        LinkedList<int[]> list = new LinkedList<>();
        for (int[] person : people) {
            int index = person[1];
            list.add(index, person);
        }

        return list.toArray(new int[list.size()][]);
    }

2、数组

    public int search(int[] nums, int target) {
        /**
         * 二分法,左闭右闭
         */
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (target == nums[mid]) {
                return mid;
            } else if (target < nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        return -1;
    }
    public int removeElement(int[] nums, int val) {
        /**
         * 遍历拷贝
         */
        int index = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == val) {
                continue;
            }
            nums[index] = nums[i];
            index++;
        }
        return index;
    }
    public int[] sortedSquares(int[] nums) {
        /**
         * 指针
         */
        int index = nums.length - 1;
        int left = 0, right = index;
        int[] ans = new int[nums.length];
        while (index >= 0) {
            if (left <= right && nums[left] < 0 && -nums[left] > nums[right]) {
                ans[index] = nums[left] * nums[left];
                left++;
            } else {
                ans[index] = nums[right] * nums[right];
                right--;
            }
            index--;
        }

        return ans;
    }
    public int minSubArrayLen(int target, int[] nums) {
        /**
         * 滑动窗口?
         * - sum:窗口内的元素和
         */
        int sum = 0;
        int left = -1, ans = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            while (sum >= target && left <= i) {
                ans = Math.min(ans, i - left);
                sum -= nums[++left];
            }
        }
        return ans == Integer.MAX_VALUE ? 0 : ans;
    }
    public int[][] generateMatrix(int n) {
        /**
         * 定义边界
         * - loop:控制绕圈的次数
         * - i,j:下标
         * - begin:每次开始循环的下标(begin,begin)
         * - count:填充的数字
         */
        int[][] ans = new int[n][n];

        int loop = 0;
        int i = 0, j = 0;
        int begin = 0;
        int count = 1;

        while (loop++ < n / 2) {
            // 左 - 右(上)
            for (j = begin; j < n - loop; j++) {
                ans[begin][j] = count++;
            }
            // 上 - 下 (右)
            for (i = begin; i < n - loop; i++) {
                ans[i][j] = count++;
            }
            // 右 - 左(下)
            for (; j >= loop; j--) {
                ans[i][j] = count++;
            }
            // 下 - 上(左)
            for (; i >= loop; i--) {
                ans[i][j] = count++;
            }
            begin++;
        }

        // 奇数
        if (n % 2 != 0) {
            ans[begin][begin] = count;
        }

        return ans;
    }

3、链表

    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;
        }
        /**
         * pHead:虚拟头节点
         * cur : 当前遍历到的节点
         * pre : 前一个节点
         */
        ListNode pHead = new ListNode(0);
        pHead.next = head;
        ListNode cur = head, pre = pHead;

        while (cur != null) {
            if (cur.val == val) {
                pre.next = cur.next;
            } else {
                pre = cur;
            }
            cur = cur.next;
        }

        return pHead.next;
    }
class MyLinkedList {

    private Node dummy;// 头指针
    private int size;// 链表长度

    class Node {// 节点类
        int val;
        Node next;

        public Node() {

        }

        public Node(int val) {
            this.val = val;
        }

    }

    public MyLinkedList() {
        size = 0;
        dummy = new Node(-1);// 虚拟头节点哈,初始化
    }

    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        Node cur = dummy.next;
        while (index > 0 && cur != null) {
            cur = cur.next;
            index--;
        }
        return cur.val;
    }

    public void addAtHead(int val) {
        Node head = dummy.next;
        Node node = new Node(val);
        dummy.next = node;
        node.next = head;
        size++;
    }

    public void addAtTail(int val) {
        Node cur = dummy;
        while (cur.next != null) {
            cur = cur.next;
        }
        Node node = new Node(val);
        cur.next = node;
        size++;
    }

    public void addAtIndex(int index, int val) {
        if (index < 0 || index > size) {
            return;
        }
        Node pre = dummy;
        Node cur = dummy.next;
        while (cur != null && index > 0) {
            pre = cur;
            cur = cur.next;
            index--;
        }
        Node node = new Node(val);
        pre.next = node;
        node.next = cur;
        size++;
    }

    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        Node pre = dummy;
        Node cur = dummy.next;
        while (cur != null && index > 0) {
            pre = cur;
            cur = cur.next;
            index--;
        }
        pre.next = cur.next;
        size--;
    }
}
    public ListNode reverseList(ListNode head) {
        /**
         * - 合理安排指针
         * - pre 、 cure 、next:指针
         */
        ListNode pre = null;
        ListNode cur = head;
        ListNode next = cur;

        // 开始遍历
        while (cur != null) {
            next = cur.next;// 保存下一个指针
            cur.next = pre;
            pre = cur;
            cur = next;
        }

        return pre;
    }
    public ListNode swapPairs(ListNode head) {
        // base
        if (head == null || head.next == null) {
            return head;
        }
        /**
         * 递归版本
         */
        ListNode next = head.next;
        ListNode node = swapPairs(next.next);
        next.next = head;
        head.next = node;

        return next;
    }

    public ListNode swapPairs02(ListNode head) {
        // base
        if (head == null || head.next == null) {
            return head;
        }
        /**
         * 合理安排指针
         * - tail:已经交换完的节点的尾节点
         * -
         */
        ListNode dummy = new ListNode(-1);
        dummy.next = head;

        ListNode nextHead = null;
        ListNode tail = dummy, cur = dummy;
        ListNode first = null;
        ListNode second = null;

        while (cur.next != null && cur.next.next != null) {
            nextHead = cur.next.next.next;// 保存下一个起始的节点
            first = cur.next;
            second = cur.next.next;
            // 开始
            second.next = first;
            tail.next = second;
            first.next = nextHead;
            // 改变指针
            cur = first;
            tail = cur;
        }

        return dummy.next;
    }
    public ListNode removeNthFromEnd(ListNode head, int n) {
        /**
         * 先走一下
         */
        ListNode dummy = new ListNode(-1);
        dummy.next = head;

        ListNode slow = dummy, fast = dummy;
        while (n > 0) {
            fast = fast.next;
            n--;
        }
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        slow.next = slow.next.next;

        return dummy.next;
    }
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        /**
         * - 快慢指针
         */
        int sizeA = getLength(headA);
        int sizeB = getLength(headB);
        ListNode big = sizeA >= sizeB ? headA : headB;
        ListNode small = big == headA ? headB : headA;

        ListNode fast = big, slow = small;
        int size = Math.abs(sizeA - sizeB);
        while (size > 0) {
            fast = fast.next;
            size--;
        }

        while (fast != null) {
            if (fast == slow) {
                return fast;
            }
            fast = fast.next;
            slow = slow.next;
        }

        return null;
    }

    // 获取head的链表长度
    int getLength(ListNode head) {
        int size = 0;
        ListNode cur = head;
        while (cur != null) {
            size++;
            cur = cur.next;
        }
        return size;
    }
    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) {
                fast = head;
                while (fast != slow) {
                    fast = fast.next;
                    slow = slow.next;
                }
                return fast;
            }
        }
        return null;
    }

4、哈希表

    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        /**
         * 需要统计每个字母出现的次数
         */
        int[] count = new int[26];

        for (int i = 0; i < s.length(); i++) {
            char cs = s.charAt(i);
            count[cs - 'a']++;
            char ct = t.charAt(i);
            count[ct - 'a']--;
        }

        for (int i = 0; i < 26; i++) {
            if (count[i] != 0) {
                return false;
            }
        }

        return true;
    }
    public int[] intersection(int[] nums1, int[] nums2) {
        /**
         * set?
         */
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < nums1.length; i++) {
            set.add(nums1[i]);
        }

        HashSet<Integer> ans = new HashSet<>();
        for (int i = 0; i < nums2.length; i++) {
            if (set.contains(nums2[i])) {
                ans.add(nums2[i]);
            }
        }
        int[] array = ans.stream().mapToInt(Integer::intValue).toArray();
        return array;
    }
    public boolean isHappy(int n) {
        /**
         * set
         */
        HashSet<Integer> set = new HashSet<>();

        while (n != 1 && !set.contains(n)) {
            set.add(n);
            n = get(n);
        }

        return n == 1;
    }

    // 返回n的平方数
    int get(int n) {
        int res = 0;
        while (n != 0) {
            int right = n % 10;
            res += right * right;
            n /= 10;
        }
        return res;
    }
    public int[] twoSum(int[] nums, int target) {
        /**
         * map,key-元素,value-元素下标
         */
        HashMap<Integer, Integer> map = new HashMap<>();

        for (int i = 0; i < nums.length; i++) {
            int rest = target - nums[i];
            if (map.containsKey(rest)) {
                return new int[]{map.get(rest), i};
            }
            map.put(nums[i], i);
        }

        return new int[]{-1, -1};
    }
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        /**
         *- map,key记录和,value记录次数
         */
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i1 : nums1) {
            for (int i2 : nums2) {
                map.put(i1 + i2, map.getOrDefault(i1 + i2, 0) + 1);
            }
        }

        int res = 0;
        for (int i3 : nums3) {
            for (int i4 : nums4) {
                res += map.getOrDefault(0 - i3 - i4, 0);
            }
        }

        return res;
    }
    public boolean canConstruct(String ransomNote, String magazine) {
        /**
         * map,key-字符,value-出现的次数
         */
        HashMap<Character, Integer> map = new HashMap<>();

        for (char c : magazine.toCharArray()) {
            map.put(c, map.getOrDefault(c, 0) + 1);
        }

        for (char c : ransomNote.toCharArray()) {
            if (!map.containsKey(c)) {
                return false;
            }
            Integer count = map.get(c);
            count--;
            if (count < 0) {
                return false;
            }
            map.put(c, count);
        }
        return true;
    }

5、字符串

    public void reverseString(char[] s) {
        /**
         * - 原地修改就涉及到交换、采用指针
         */
        int left = 0, right = s.length - 1;
        while (left < right) {
            swap(left, right, s);
            left++;
            right--;
        }
    }

    void swap(int i, int j, char[] s) {
        // 交换的方法
        char c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
    public String reverseStr(String s, int k) {
        /**
         *
         */
        char[] chars = s.toCharArray();
        int index = 0;// 字符串开始翻转的起始位置
        while (index < chars.length) {
            // 判断剩余字符的个数和k的关系
            if (chars.length - index <= k) {
                // 将剩余字符全部翻转
                int left = index, right = chars.length - 1;
                while (left < right) {
                    swap(left, right, chars);
                    left++;
                    right--;
                }
            } else {
                // 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
                int left = index, right = index + k - 1;
                while (left < right) {
                    swap(left, right, chars);
                    left++;
                    right--;
                }
            }
            index += 2 * k;
        }

        return String.valueOf(chars);
    }

    void swap(int i, int j, char[] chars) {
        char c = chars[i];
        chars[i] = chars[j];
        chars[j] = c;
    }
    public String replaceSpace(String s) {
        /**
         * append?
         */
        StringBuilder sb = new StringBuilder();
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == ' ') {
                sb.append("%20");
            } else {
                sb.append(chars[i]);
            }
        }

        return sb.toString();
    }
    public String reverseWords(String s) {
        /**
         * 拼接字符串
         */
        String ans = "";
        // 开始遍历
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == ' ') {
                continue;
            }
            int left = i, right = left + 1;
            while (right < chars.length && chars[right] != ' ') {
                right++;
            }

            ans = s.substring(left, right).concat(" ").concat(ans);
            i = right;
        }

        return ans.substring(0, ans.length() - 1);
    }
    public String reverseLeftWords(String s, int n) {
        if (s == null) {
            return s;
        }
        /**
         *
         */
        String substring = s.substring(0, n);
        return s.substring(n, s.length()).concat(substring);
    }
    public int strStr(String haystack, String needle) {
        /**
         * next:前缀表数组
         */
        int[] next = getPrefixArray(needle);

        // 遍历haystack元素,开始匹配
        int j = 0;// 模式串下标-needle
        for (int i = 0; i < haystack.length(); i++) {
            // 回退,需要连续回退
            while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
                j = next[j - 1];
            }
            if (haystack.charAt(i) == needle.charAt(j)) {
                j++;
            }
            if (j == next.length) {
                return i - next.length + 1;
            }
        }

        return -1;
    }

    // 求字符串s的前缀表数组
    int[] getPrefixArray(String s) {
        int[] next = new int[s.length()];
        int j = 0;
        next[0] = 0;
        for (int i = 1; i < s.length(); i++) {
            while (j > 0 && s.charAt(j) != s.charAt(i))
                j = next[j - 1];
            if (s.charAt(j) == s.charAt(i)) {
                j++;
            }
            next[i] = j;
        }
        return next;
    }
    public boolean repeatedSubstringPattern(String s) {
        /**
         * 本体为 KMP 的变式,可以看作将两个字符串s拼接后是否能凑出一个s
         */
        int[] next = getNext(s);
        int len = s.length();
        // 为什么?
        /**
         * 假设字符串s使用多个重复子串构成(这个子串是最小重复单位),重复出现的子字符串长度是x,所以s是由n * x组成。
         * 因为字符串s的最长相同前后缀的长度一定是不包含s本身,所以 最长相同前后缀长度必然是m * x,而且 n - m = 1,(这里如果不懂,看上面的推理)
         *
         * 所以如果 nx % (n - m)x = 0,就可以判定有重复出现的子字符串。
         */
        if (next[len - 1] > 0 && len % (len - next[len - 1]) == 0) {
            return true;
        }

        return false;
    }

    int[] getNext(String s) {
        int[] next = new int[s.length()];
        int j = 0;// 维护下标
        for (int i = 1; i < s.length(); i++) {
            while (j > 0 && s.charAt(i) != s.charAt(j)) {
                // 需要考虑连续回退
                j = next[j - 1];
            }
            if (s.charAt(i) == s.charAt(j)) {
                j++;
            }
            next[i] = j;
        }

        return next;
    }

总结

提示:这里对文章进行总结:

这几天在刷题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值