二刷Leetcode-Days01

数组:

    /**
     * 704. 二分查找
     * @param nums 升序无重复的整型数组
     * @param target 目标值
     * @return 函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
     */
    public int search(int[] nums, int target) {
        // 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }
        // 前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的
        // 此时可以考虑二分查找法
        int left = 0;
        // 二分法区间的定义一般为两种,左闭右闭即 [left, right],或者左闭右开即 [left, right)。
        // right大小为数组长度,right = nums.length 显然此时二分查找的区间是 [left,right)
        int right = nums.length;
        // 左闭右开的区间,while判定要符合区间的规范,当 left <= right 时,显然不符合 [left,left) 的定义,没有意义
        // 如果要用 while(left <= right) 对应左闭右闭的情况,那么此时 right = num.length - 1
        while (left < right) {
            // 每一次边界的处理都要坚持根据区间的定义
            int mid = left + (right - left) >> 1;
            if (nums[mid] > target) {
                // 区间右开不包含right值,num[right]没有比较过,所以此时 target 在 [mid, right) 范围里
                right = mid;
            } else if (nums[mid] < target){
                // 区间左闭包含left值,nums[left]已经比较过了,所以此时 target 在 [left + 1, mid) 范围里
                left = mid + 1;
            } else {
                // 数组中找到目标值,直接返回下标
                return mid;
            }
        }
        // 未找到目标值
        return -1;

        //************左闭右闭************//
        // int left = 0;
        // // 定义target在左闭右闭的区间里,[left, right]
        // int right = nums.length - 1;
        // // 当 left=right时,区间 [left, right] 合法,比如 [3, 3]
        // while (left <= right) {
        //     int mid = left + (right - left) >> 1;
        //     if (nums[mid] < target) {
        //         // 区间包含left值,nums[left]比较过,所以此时 target 在 [left + 1, mid) 范围里
        //         left = mid + 1;
        //     } else if (nums[mid] > target) {
        //         // 区间包含right值,num[right]比较过,所以此时 target 在 [mid, right - 1] 范围里
        //         right = mid - 1;
        //     } else {
        //         return mid;
        //     }
        // }
        // return -1;
    }

 链表:

    /**
     * 203. 移除链表元素
     * @param head 链表的头节点
     * @param val 整数
     * @return 删除链表中所有满足 Node.val == val 的节点,并返回新的头节点
     */
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;
        }
        // 不设置虚拟头结点的方法比较麻烦,需要先对头结点进行处理,再处理后续结点,略...
        // 操作链表时通常设置一个虚拟头结点再进行操作(便于操作头结点,统一全部节点的操作方式)
        // 也可以直接写成 ListNode dummyHead = new ListNode(-1, head);
        ListNode dummyHead = new ListNode(-1);
        // 将虚拟头结点指向 head,方面后面的操作
        dummyHead.next = head;
        ListNode cur = dummyHead;
        while (cur.next != null) {
            if (cur.next.val == val) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }
        // dummyHead.next 才是真正新的头结点
        return dummyHead.next;
        
        // *********递归**********//
        // head.next = removeElements(head.next, val);
        // return head.val == val ? head.next : head;
    }

哈希表:

    /**
     * 242. 有效的字母异位词
     * @param s 字符串 s
     * @param t 字符串 t
     * @return 判断 t 是否是 s 的字母异位词
     * (若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。)
     */
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        // 容易想到26个字母,用数组就可以表示,遍历数组判断是否是 0 就可以得到结果
        // 用 map 一个道理,map.put(ch, map.getOrDefault(ch, 0) + 1); 初始化默认 0 + 1
        int[] res = new int[26];
        for (int i = 0; i < s.length(); i++) {
            // 并不需要记住字符 a 的ASCII,只要求出在 res 数组内的位置就可以
            res[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < t.length(); i++) {
            res[t.charAt(i) - 'a']--;
        }
        for (int cnt : res) {
            if (cnt != 0) {
                return false;
            }
        }
        return true;

        // 充分利用 lambda 表达式
        // int[] cnt = new int[26];
        // t.chars().forEach(tc -> cnt[tc - 'a']++);
        // s.chars().forEach(sc -> cnt[sc - 'a']--);
        // return Arrays.stream(cnt).allMatch(c -> c == 0);
    }

数组:

    /**
     * 344. 反转字符串
     * @param s 将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出
     * 不要给另外的数组分配额外的空间,必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
     */
    public void reverseString(char[] s) {
        int left = 0;
        int right = s.length - 1;
        // 此处和二分查找中的区间定义一样,不同的是 left = right 可以跳过不判断
        while (left < right) {
            // 需要一个临时变量用于交换
            char temp = s[left];
            s[left] = s[right];
            s[right] = temp;
            left++;
            right--;
        }
    }
posted @ 2023-05-11 10:13  LinxhzzZ  阅读(13)  评论(0)    收藏  举报