冗长的必经之路
Day1
27.移除数组
题目:移除数组
首先想到非常丑陋的循环遍历的方法
class Solution {
public int removeElement(int[] nums, int val) {
int len=nums.length;
for(int i=0;i<len;i++)
{
if(nums[i]==val)
{
for(int j=i+1;j<len;j++)
{
nums[i]=nums[j];
}
len--;
i--;
}
}
return len;
}
}
以上需要注意两点:1循环边界的问题:len=len-1;2当i个值找到目标值时记得在删除后更新i
问题:内存开销太大
一些改进:快慢指针
核心思想:当找到对应的nums[i]==val时,快指针指向下一个位置,但是慢指针不变,以便于在查找过程中用快指针的值替代慢指针指向的值。O(n)解决。
快指针:获取新数组元素
慢指针:更新位置
重点:由快指针承担对比工作
边界:直接输出slow就行,因为从0开始
类似题目:26删除有序数组重复项
思路:把条件替换成,条件语句里的是找不到目标时的操作,重复项中目标为重复项,if不重复就可以替换了
if(nums[fast]!=nums[slow])
提问:如果非有序数组怎么处理
997.有序数组平方
997
初步想法:平方结合排序/判断是否是负数,如果负数就排序不是负数不管
存档: 快排
解决办法: 依旧是快慢双指针
数组问题中只要涉及到排序换位置全部可以用快慢指针解决;
这里引入一个int[]result 用来存放改位置后的内容
需要注意while中的条件,要保证每一个位置都比较到;明确一个条件:当left=right时也需要把平方后的内容存入新数组,所以必须是<=。
class Solution {
public int[] sortedSquares(int[] nums) {
int left=0;
int right=nums.length-1;
int[] result=new int[nums.length];
int index=nums.length-1;
while(left<=right)
{
if(nums[left]*nums[left]>nums[right]*nums[right])
{
result[index--]=nums[left]*nums[left++];
}
else
{
result[index--]=nums[right]*nums[right--];
}
}
return result;
}
}
类似的:合并有序数组
需注意结束条件:第二个数组全部插入就结束
思考:以上碰到的问题都是有序数组如果无序该用什么套路?
209长度最小的子数组
目的时找到子序列的长度,需要flag,不断调整。
重要概念:滑动窗口。暴力解遍历所有序列。
重要第一步:什么时候退出循环?
for(int right=0; right<nums.length; right++)
{
sum=sum+nums[right];//累加后调节窗口
//1.sum值>target;2,调节窗口到不大于target为止
while(sum>=target)
{//调节窗口的操作:1result值更新;2窗口左区间往右移一格之后的sum值}
}
59螺旋矩阵
矩阵:数组进入二维模式
思路:范围定为n平方。螺旋但是第一层确定,第二层左n-1个顺序,最右是第一层右+1;上半层从左往右顺序,下班层从右往左。
此思路大错特错。一道控制非常多条件的题。
确实要分层,也叫循环,n、2。
控制原则:左开右闭,要保持一致。
class Solution {
public int[][] generateMatrix(int n) {
int[][]res=new int[n][n];
int loop=0;
int start=0;
int count=1;//不知道是干什么的
int i,j;
while(loop<n/2)
{
for(j=start;j<n-loop-1;j++)
{
res[start][j]=count++;
}
for(i=start;i<n-loop-1;i++)
{
res[i][j]=count++;
}
for(;j>loop;j--)
{
res[i][j]=count++;
}
for(;i>loop;i--)
{
res[i][j]=count++;
}
start=start+1;
loop=loop+1;
}
if(n%2==1)
{
res[start][start]=count;
}
return res;
}
}
Day2链表内容
链表定义
public class ListNode{
int val;
ListNode next;
public ListNode(){}
public ListNode(int val){this.val=val;}
public ListNode(int val,ListNode next){
this.val=val;
this.next=next;}
}
移除链表
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head==null)
return head;
ListNode dummyHead=new ListNode(-1,head);//虚拟头节点
ListNode pre=dummyHead;
ListNode cur=head;
while(cur!=null)
{
if(cur.val==val){ pre.next=cur.next;}
else { pre=cur;}
cur=cur.next;
}
return dummyHead.next;
}
}
类似的: 237这道题在不知道pre节点的时候应该怎么操作
707设计链表
class ListNode{
int val;
ListNode next;
ListNode(){}
ListNode(int val){this.val=val;next=null;}
}
class MyLinkedList {
ListNode head;
int size;
public MyLinkedList() {
size=0;
head=new ListNode(0);
}
public int get(int index) {
if(index<0||index>=size)
{
return -1;
}
ListNode cur=head;
for(int i=0;i<=index;i++)
{
cur=cur.next;
// System.out.print(cur.val);
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(size,val);
}
public void addAtIndex(int index, int val) {
if(index>size)
{
return;
}
ListNode cur=new ListNode(val);
ListNode pred=head;
if(index<0)
{
//cur.next=head;
//head=cur;
index=0;
}
for(int i=0;i<index;i++)
{
pred=pred.next;
}
cur.next=pred.next;
pred.next=cur;
size++;
}
public void deleteAtIndex(int index) {
ListNode pred=head;
if(index<0||index>=size)
{
return ;
}
size--;
if(index==0)
{
head=head.next;
return ;
}
for(int i=0;i<index;i++)
{
pred=pred.next;
}
pred.next=pred.next.next;
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
206翻转链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre=null;
ListNode cur=head;
while(cur!=null)
{
ListNode temp=cur.next;
cur.next=pre;
pre=cur;
cur=temp;
}
return pre;
}
}
二刷写出非常搞笑的错误:注意
class Solution {
public ListNode reverseList(ListNode head) {
ListNode dummynode=new ListNode();
ListNode cur=head;
ListNode pre=dummynode;
ListNode temp;
while(cur!=null)
{
temp=cur.next;
cur.next=pre;
pre=cur;
cur=temp;
}
return pre;
}
}
返回的链表带了【0】尾巴。首先不需要有一个虚拟头节点,pre就够了
24两两交换链表节点
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyhead=new ListNode();
dummyhead.next=head;
ListNode cur=dummyhead;
ListNode temp1;
ListNode temp2;
while((cur.next!=null)&&(cur.next.next!=null))
{
temp1=cur.next;
temp2=cur.next.next.next;
cur.next=temp1.next;
cur.next.next=temp1;
temp1.next=temp2;
cur=temp1;
}
return dummyhead.next;
}
}
19删除链表的倒数第n个结点
是不是也可以用前后指针,倒数第n个节点,然后让前指针在前面趟路,前指针走了n步之后后指针走路.一遍过。
注意:last指针要指向即将删除的节点的前一项。以便删除。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyhead=new ListNode();
dummyhead.next=head;
ListNode cur;
ListNode last;
cur=dummyhead;
last=dummyhead;
while(cur.next!=null)
{
if(n<1)
{
last=last.next;
}
cur=cur.next;
n=n-1;
}
last.next=last.next.next;
return dummyhead.next;
}
}
0207链表相交
长的链表先移到跟短链表齐平时的节点:
之后比较指针。比较墨迹。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//求长度
ListNode cur=headA;
int lista=0;
while(cur!=null)
{
lista++;
cur=cur.next;
}
cur=headB;
int listb=0;
while(cur!=null)
{
listb++;
cur=cur.next;
}
int compare=listb-lista;
ListNode temp;
ListNode cura=headA;
ListNode curb=headB;
if(compare<0)
{
while(compare<0)
{
cura=cura.next;
compare++;
}
}
else
{
while(compare>0)
{
curb=curb.next;
compare--;
}
}
int count=0;
while(cura!=null)
{
if(cura==curb)
{
count++;
}
cura=cura.next;
curb=curb.next;
}
if(count==0)return null;
else
{
while(lista-count>0)
{
headA=headA.next;
lista--;
}
return headA;
}
}
}
142环形链表
需要解决:1.怎么判断有环 2.怎么确定环起始位置
1.使用快慢指针,两指针会相遇即有环。
2. 两指针相遇时地点index1,设head到入环点为x,入环点到index1为y,index1再绕回入环点距离为z:2(x+y)=x+y+(n)(y+z)
3. x=(n-1)(y+z)+z意味着当找到相遇点index1,只需要让慢指针重新从head遍历,快指针不变,再次相遇时位置必然是入环点。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head;
ListNode slow=head;
int flag=0;
ListNode index1;
ListNode index2=head;
while((fast!=null)&&(slow!=null)&&(flag!=1))
{
if(fast.next==null)
{
return null;
}
fast=fast.next.next;
slow=slow.next;
if(fast==slow)//这部分必须放在fastslow往后走之后否则flag永远是1
{
flag=1;
index1=fast;
}
}
if(flag==0)
{
return null;
}
else
{
while(index2!=fast)
{
index2=index2.next;
//我觉得都已经进行到这一步了肯定是有环的啊。无环已经返回了
fast=fast.next;
//之前的问题在于找到入口点时fast指针只向后走一个节点
}
return index2;
}
}
}//我的index1好像没有意义
链表部分结束