开个贴记录自己在刷leetcode时部分题目的思路,以及在编写时漏掉的一些代码细节,学习到的一些代码技巧~~
主要用到了二分法进行查找,注意左右边界的选择(我选左闭右开),此外就是在求中间的下标时,定义int middle = left + (right - left) / 2 效果 等同于(left + right)/2,但是用前者可以防止溢出,例如left和right都是最大int时,left + right会越界。
讨论4种情况:
1.目标在数组所有元素之前
2.目标等于数组中的某一个元素
3.目标插入数组中的位置
4.目标在数组所有元素之后
除了能找到target返回middle,此外都返回left 或 right +1
开始:第一个等于target的
结束:第一个大于target-1
没有找到元素:返回[-1,-1]
思路不对,留个坑吧~~
双指针法
采用快慢指针法。若使用暴力解法:注意i-- 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位,否则会跳过i后面一位
最后返回的时候,记住返回slow+1,因为总长度为slow+1,slow从0开始
还是slow的问题,因为判断完nums[fast] != 0后slow会进行自增++,所以总长为slow,数组下标为slow-1;
新思路:数组其实是有序的, 只不过负数平方之后可能成为最大数了。
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
滑动窗口法
窗口的长度不一样长!
满足条件时:
left++,再判断if,满足则left继续右移动,缩小窗口;不满足则right++,一直到right到右边界
不满足条件:
right++,直到满足条件
如果窗口中元素的和大于target,就开始缩小窗口,然后更新最小滑动窗口
2.其他条件下思路也一样
3.遗忘
Int(4字节)
Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
Integer.MIN_VALUE表示int数据类型的最小取值数:-2 147 483 648
左边界的移动:
如果当前字符包含在 map中,此时有2类情况:
(1)如:abca,当我们遍历到第二个a,当前有效最长子段是 abc,我们又遍历到a,此时更新 left 为map.get(a)+1=1,
当前有效子段更新为 bca;
(2)如:abba,我们先添加a,b进map,此时left=0,我们再添加b,发现map中包含b, left=map.get(b)+1=2,
此时子段更新为 b,而且map中仍然包含a,且map.get(a)=0;
随后,我们遍历到a,发现a包含在map中,且map.get(a)=0,如果像(1)一样处理,就会发现 left=map.get(a)+1=1,实际上,left此时应该不变,left始终为2,子段变成 ba才对。因此:
left=Math.max(left ,map.get(c)+1).
1.条件为fast != null,需要走n+1步
for(int i = 0; i < n + 1 ; i++){
fast = fast.next;
}
while( fast != null){}
2.条件为fast.next != null,走n步
for(int i = 0; i < n ; i++){
fast = fast.next;
}
while( fast.next != null){}
注意:边界条件:i
循环遍历链表长度时,使用cur.next报错-空指针异常——>错误原因:没有考虑[ ]空链表的情况
正确写法:
int sizeB = 0;
while(curA != null){
sizeA++;
curA = curA.next;
}
要点:
答:快慢指针,重合则有环
2. 如何找到入环点
2(x+y)=n(z+y)+y+x
小技巧:record[s.charAt(i) - 'a']++;
若s.charAt(i)为z,则相减表示z-a之间的差距:25,即record[25];若为a,则record[0]
在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中
新方法:Map.getOrDefault(key,默认值);
如果 在Map中存在key,则返回key所对应的value。如果 在Map中不存在key,则返回默认值。
省去了if判断
在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,费时
留坑:为什么内层循环不用剪枝?
除了使用StringBulider的reverse()方法外,可以使用双指针,^异或运算
// 使用异或交换元素 底层实际是二进制码之间的异或运算
如:a ^ b => 97 ^ 98 = 3
即0110 0001 ^0110 0010 = 00000011=3
具体步骤为:
翻转单个单词:
for(int fast = 1;fast < A.length; fast++)
if(A [fast] == ' '){
reverseAll(A,slow,fast - 1);
slow = fast + 1;
}
if(fast == A.length - 1){
reverseAll(A,slow,fast);
}
}
条件可改在一起判断,即:
for(int fast = 1;fast <= A.length; fast++){
if(fast == A.length||A [fast] == ' '){
......
}
}
必须是A.length在前,否则当fast为长度时,先判断A[fast]会导致下标越界
KMP算法
KMP主要应用在字符串匹配上。—— K 快速 M模板 P匹配
主要思想:当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配。
next数组:前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。
最后返回 return i - needle.length() + 1;
// 判断是否能整除
if(next[尾]> 0 && N % (N-next[尾]) == 0){
return true;
}
最大前后缀不包含的地方 ——> 公共的
长度能够整除公共 ——>重复
在取栈中的元素时,字符串的拼接可以实现反转
String str = "";
while (!deque.isEmpty()) {
str = deque.pop() + str;
}
如第一次pop()为 a,则str=a;第二次pop()为h,
则 str=h+a=ha,实现(ah)——>ha,注意str的拼接顺序!
Integer.valueOf(tokens[i]) 把字符转换成int
for (String s : tokens)等价于
for(int i = 0; i < tokens.length; i++)
token[i]==s
PriorityQueue heap = new PriorityQueue<>((n1,n2) -> n1-n2);
比较规则就是n1-n2,Comparator函数式接口的Lambda表达式写法: () -> {};, ()里面是参数列表,{}里面是方法体,方法体只有一行时{}可以省略
2. Map.Entry
Map.Entry是Map的一个内部接口。此接口为泛型,定义为Entry
Map提供了一些常用方法,
int a[] =new int {1,2,3} ;
int a[] = {1,2,3} ;
3. pq.poll()[0]的0和1怎么确定?
二叉树的遍历方式:两种方式都有前中后序三种遍历顺序
前:中左右
中:左中右
后:左右中
(1)递归遍历
统一模板:(前中后序只需改变顺序即可)
//前序遍历
class Solution {
public List preorderTraversal(TreeNode root) {
List result = new ArrayList();
preorder(root, result);
return result;
}
public void preorder(TreeNode root, List result) {
if (root == null) {
return;
}
result.add(root.val); //中
preorder(root.left, result); //左
preorder(root.right, result); //右
}
}
没有统一模板,中序略有不同,因为前序遍历中访问节点(遍历节点)和处理节点(将元素放进result数组中)可以同步处理,但是中序就无法做到同步!
中序:
class Solution {
public List inorderTraversal(TreeNode root) {
List result = new ArrayList<>();
if (root == null){
return result;
}
Stack stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()){
if (cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}
后序:调整一下前序遍历的代码顺序,变成中左右入栈最后在反转result集合——>使用collections接口
Collections.reverse(result);
return result;
层序遍历可以使用递归方式,或者借组队列:代码参见