二刷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--; } }

浙公网安备 33010602011771号