yubのAlgorithm.0x2
移除元素link:27. 移除元素 - 力扣(LeetCode)
思路分析1.常规遍历数组,比较vaule值是否相等,若不相等往前拷贝覆盖即可,相等跳过,更新下标(可以理解为数组长度减少).【时间复杂度O(n) 空间复杂度O(1)】2.快慢指针.快指针遍历进行筛选,慢指针对应常见存储的数组.找到目标vaule后fast和slow指针拉开距离开始遍历维护更新.【时间复杂度O(n) 空间复杂度O(1)】
拷贝覆盖123456789101112class Solution { public int removeElement(int[] nums, int val) { int k = 0; for(int num:nums){ if(num != val){ nums[k] = num; k++; } } return k; } ...
yubのAlgorithm.0x3
有序数组的平方link:977. 有序数组的平方 - 力扣(LeetCode)非递减顺序一个数列中的元素从左到右依次不减,或者说不降序排列.比如:1233445,12345.
思路分析如果看到数组能条件反射到双指针那已经是win了.根据题意平方之后的数一定在数组的两端.两个指针一首一尾,从后往前更新数组.
1234567891011121314151617181920class Solution { public int[] sortedSquares(int[] nums) { //非递减数组可得最大值平方后会出现在数组两头 int left = 0; int right = nums.length - 1; int[] result = new int[nums.length]; int index = result.length - 1 ; while(left <= right) { if(nums[left]*nums[left] > nums[right ...
yubのAlgorithm.0x5
反转链表link:206. 反转链表 - 力扣(LeetCode)
思路分析与数组不同,链表没必要定义新的链表进行存储【对内存空间的浪费】直接改变next指针即可.注意头节点指向的下一个节点为null
双指针法123456789101112131415161718class Solution { public ListNode reverseList(ListNode head) { //双指针操作 ListNode prev = null; ListNode cur = head; //记录节点 ListNode temp = null; while(cur != null) { temp = cur.next;//保存下一个节点 cur.next = prev; //赋值之后整体向后移动//注意先移动prev 不如cur已经移动后记录不到prev新的位置 prev = cur ...
yubのAlgorithm.0x4
移除列表元素link:203. 移除链表元素 - 力扣(LeetCode)
首先单向链表是有一个数据域和指针域且在内存中不连续.链表的查找需要从头往后一个个查找【时间复杂度为O(n)】,但是数组查找只需要访问对应元素下标即可【时间复杂度为O(1)】.查找频繁:数组是更好的选择,因为通过索引访问的时间复杂度是 O(1),链表则需要遍历.
插入/删除频繁:链表更适合,因为它可以高效地插入和删除元素,时间复杂度为 O(1)(假设已找到插入或删除位置)。相反,数组在插入和删除时需要移动大量元素,时间复杂度为 O(n).
思路分析看到题目最第一反应就是常规解法,遍历链表找到target直接进行删除操作.【目标是头节点和不是头节点两种情况】(其实还是想有更优雅的解法 不用单独处理移除头节点的情况)
直接删除1234567891011121314151617181920212223class Solution { public ListNode removeElements(ListNode head, int val) { if(head == null)& ...
yubのAlgorithm.0x8
两个数组的交集link:349. 两个数组的交集 - 力扣(LeetCode)
思路分析首先想到合并两个数组,遍历找重复项存储到新的数组中但其实用HashSet是更加方便的,【HashSet不存在重复数据】
**注意:使用数组做哈希表的题目都限制了大小 例如只有小写字母或者数值大小在【0-1000】内 **
HashSet12345678910111213141516171819202122232425262728293031import java.util.HashSet;import java.util.Set;class Solution { public int[] intersection(int[] nums1, int[] nums2) { if(nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0 ) { return new int[0]; } //创建需要的set表 ...
yubのAlgorithm.0x9
两数之和link:1. 两数之和 - 力扣(LeetCode)
思路分析看到题目描述首先想到用两层for循环解决问题.分别从i位置和j(i+1)位置开始相加遍历判断.注意不越界条件
数组1234567891011121314151617181920212223242526class Solution { public int[] twoSum(int[] nums, int target) { //我们要找到2个数之和等于target //即我们需要找到nums[i] + nums[j] == target,并且返回他们的下标(i和j),其中i != j int[] ans = new int[2]; //声明一个大小为2的数组用来保存结果 //我们通过循环来遍历所有的数字 int n = nums.length; //用一个变量n保存nums的长度 //i为第一个数的下标,nums一共有n个数,所以i的取值范围是[0, n-1] for(int i = 0; ...
yubのAlgorithm.0xa
赎金信link:383. 赎金信 - 力扣(LeetCode)
思路分析关键分析觉得是次数统计,ransomNote中的字符出现次数和magazine中统计次数相同即可.(有点相同字母异序词的味->哈希数组实现【大小写转换】)题目又说是两个字符串全为小写字母,有数量限制(少量).方便进行映射.可以暴力两层for循环求解,但又想到先前接触的哈希map进行映射.
Tip本题目使用map消耗的空间资源比数组大一些.map要维护红黑树或哈希表还要做哈希函数,更费时.【数据量大时更能体现】
数组1234567891011121314151617181920212223class Solution { public boolean canConstruct(String ransomNote, String magazine) { //创建需要的数组和中间汴梁 int[] arr = new int[26]; int tmp = 0; //遍历rans 在magazine中映射确定 下标位置标记逐增 ...
yubのAlgorithm.0xb
反转字符串link:344. 反转字符串 - 力扣(LeetCode)
思路分析其实最开始学C语言的时候,也遇到过类似题目.当时自以为的投机取巧无非只是倒序打印而不是逆置元素.(hh 果然小白都会这样 当然也有更聪明的小懒狗直接用库函数 【及其不推荐】
双指针1234567891011121314class Solution { public void reverseString(char[] s) { int left = 0; int right = s.length - 1; while(left < right) { char tmp = s[left]; s[left] = s[right]; s[right] = tmp; right--; left++; } }}
Tip
更优雅的处理方式——异或因为a ^ a = 0,b ...
yubのAlgorithm.0xc
反转字符串IIlink:541. 反转字符串 II - 力扣(LeetCode)
思路分析关键点在于我们要找对反转思路,2k是一个区间,没达到条件和达到条件之后怎么处理.因此考虑怎么筛选条件.
首先创建一个字符数组用于存储遍历的下标位置用于筛选【其实类似双指针判断 此时尾指针的判断 避免越界】判断区间为[数组长度-1,起始位置 + k - 1]
12345678910111213141516171819class Solution { public String reverseStr(String s, int k) { char[] ch = s.toCharArray(); for(int i = 0;i < ch.length;i += 2*k) { int start = i; //防止越界 平移判断区间和length比较 int end = Math.min(ch.length -1 ,start + k - 1); ...
yubのAlgorithm.0xd
用栈实现队列link:232. 用栈实现队列 - 力扣(LeetCode)
思路分析首先理清楚栈和队列的异同.队列是先进先出 栈先进后出【两者都能存储元素】再来看peek()和poll().栈和队列都有peek() 可以称之为“瞄一眼”只是看一下当前栈顶/队头元素是什么.栈中的pop()直接返回栈顶元素(出栈)队列中的poll()在某种层面上就等效于pop()了.
先用栈1存储所有元素 再逐个pop到栈2中最后pop栈2全部元素.注意判断栈满(是否需要扩容)
12345678910111213141516171819202122232425262728293031323334353637383940414243444546class MyQueue { private Stack<Integer> stack1; private Stack<Integer> stack2; public MyQueue() { stack1 = new Stack<>(); stack2 = new ...