234、回文链表
给你一个单链表的头节点 head
,请你判断该链表是否为回文链表。如果是,返回 true
;否则,返回 false
。
首先是考虑使用翻转链表,但是不行 (翻转代码如下:相当于自己又复习一遍翻转链表的力扣题)
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
ListNode Next=cur.next;
cur.next=pre;
pre=cur;
cur=Next;
}
return pre.val==head.val;
}
}
首先是考虑使用翻转链表,但是不行
1:在进行翻转的时候,已经破坏了链表的结构了,此时实际就只有一个链表,是在原链表上反转的,那head最后指向反转后链表的尾部了,没办法往回遍历的
2:除非构建一个新表,将head的结构复制到新表上,在和翻转后的head表进行对比(建表有点麻烦,要ListNode res = new ListNode();//创建新的链表,之后每一次循环都要res.next=new ListNode(0);)
所以用翻转的思路进行修改
注意:reverse的方法,所以要先把sb原先的值赋给别人再去翻转
法一:使用StringBuilder的reverse()
class Solution {
public boolean isPalindrome(ListNode head) {
//链表中节点数目在范围[1, 10^5] 内
StringBuilder sb=new StringBuilder();
ListNode temp=head;
while(temp!=null){
sb.append(temp.val);
temp=temp.next;
}
String original=sb.toString();
String reverse=sb.reverse().toString();
return original.equals(reverse);
}
}
知识回顾:equals与==的区别
1、首先的区别是,equals 是方法,而 == 是操作符;
2、== 只能用在8种基本数据类型
注意:字符串的常量池不属于堆、栈
栈内存里面存放基本类型的变量和对象的引用变量
堆内存里面存放数组和new创建的对象。
法二:数组的方法:可以将结点的值添加到数组里,然后遍历数组判断回文————执行速度会比reverse的快
用数组的方法其实跟用list的方法一样。list.get(索引)来获取元素
class Solution {
public boolean isPalindrome(ListNode head) {
int len = 0;
// 统计链表长度
ListNode cur = head;
while (cur != null) {
len++;
cur = cur.next;
}
cur = head;
int[] res = new int[len];
// 将元素加到数组之中
for (int i = 0; i < res.length; i++){
res[i] = cur.val;
cur = cur.next;
}
// 比较回文
for (int i = 0, j = len - 1; i < j; i++, j--){
if (res[i] != res[j]){
return false;
}
}
return true;
}
}
list集合的方法
法三:1、链表的问题→双指针→快慢指针
2、回文→翻转→因为全部翻转不行,那么就考虑将链表一分为二(保留头结点的结构不变,因为翻转后,要将题目的链表和翻转的链表进行对比,所以要保留题目的链表的头结点那一块的结构不变,才可以和翻转后的链表进行比较)
因为要将链表一分为二,所以要考虑链表的长度是奇数还是偶数:
链表中有四个结点,那么退出while循环: 快慢指针走了两次循环,即慢指针从结点1走到了结点3
链表中有五个结点,那么退出while循环: 快指针在链表的末尾结点,慢指针在链表的中间结点,这时候慢指针要额外走一步,慢指针就从结点1走到结点4,这样才可以判断前面两个结点和后面两个结点(中间的结点3不比较)
/**
* 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 boolean isPalindrome(ListNode head) {
//快慢指针 反转链表
ListNode fast = head;
ListNode slow = head;
//快慢指针找中点 反转链表要分奇偶讨论
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
if(fast != null){//链表长度是奇数的情况
slow=slow.next;//奇数结点时 slow指向中间 此时slow+1 跟偶数统一 反转链表
}
slow = reverse(slow);
fast = head;
while(slow != null){//用slow!=null来当做循环条件
//是因为链表长度是奇数(5)时:一分为二的链表前面3个结点,后面2两个结点,
//只需判断前面的2个结点和后面的2个结点的值是否一样
//偶数就正常前面2个结点,后面2个结点判断。
if(fast.val != slow.val)return false;
fast = fast.next;
slow = slow.next;
}
return true;
}
//实现反转链表方法
ListNode reverse(ListNode head){
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
237、删除链表中的节点
请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点 。题目数据保证需要删除的节点 不是末尾节点 。
分身!!
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* ListNode(){}
* }
*/
class Solution {
public void deleteNode(ListNode node) {
//只能访问以node开头的相关的结点
node.val=node.next.val;
node.next=node.next.next;
}
}
549、最长和谐子序列
和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。现在,给你一个整数数组 nums ,请你在所有可能的子序列中找到最长的和谐子序列的长度。数组的子序列是一个由数组派生出来的序列,它可以通过删除一些元素或不删除元素、且不改变其余元素的顺序而得到。
示例1:和谐数组可以有:[1, 2, 2, 2] 和 [2, 2, 2, 3, 3]
/* map.put(1,1);
map.put(1,2);
map.put(1,3);
System.out.println(map.get(1));-----3 */
因为map里键不能重复,而值可以重复。所以如果有键重复的,那么他就会覆盖上一次的,即键若出现重复,则看最后一次的键和值才是真正的。
class Solution {
//和谐数组里面的元素只有两个数但是可以重复
// map<k,v> k:nums[i] v:出现重复元素的次数
public int findLHS(int[] nums) {
Map<Integer,Integer>map=new HashMap<>();
int maxLength=0;
//记录数组元素以及他们的次数
for(int i=0;i<nums.length;i++){
if(map.containsKey(nums[i])){
map.put(nums[i],map.get(nums[i])+1);
}else{
map.put(nums[i],1);
}
}
//判断是否有元素1 +1 即元素2的存在,如果有,那么和谐数组的长度就是1的出现的次数+2出现的次数
//有点动态规划?
for(int i:map.keySet()){
if(map.containsKey(i+1)){
maxLength=Math.max(maxLength,map.get(i)+map.get(i+1));
}
}
return maxLength;
}
}