網站首頁 編程語言 正文
問題
如果字符串存儲在單鏈表中,怎么快速判斷這個字符串是否是回文字符串?
知識點
快慢指針、鏈表反轉
實現思路
一般方法 復雜度為O(n2)
- 如果字符串存儲在數組中,那么只需要判斷第一個和最后一個這么一一對應下去,判斷字符是否相同,還是比較簡單的。
- 如果單鏈表中存儲也參照這種方法,那么可以定義兩個指針,一個初始指向頭部,一個初始指向尾部,后續依次一個向后指一個依次向前指。這樣也能判斷是否是回文字符串。但是對于單鏈表,查找前繼節點,需要遍歷鏈表,所以復雜度是O(n2)
復雜度為O(n)的方法
- 如果使用單鏈表存儲,那么第一步需要找到鏈表的中間節點,這一步需要用到快慢指針
- 第二步需要將單鏈表的后半部分進行反轉,單鏈表的反轉
代碼
定義鏈表結構
/**
* 單鏈表的節點類
*
* @author StoneYu
* @date 2022/09/25
*/
@Data
@AllArgsConstructor
public class SinglyLinedNode<T> {
T data;
SinglyLinedNode<T> next;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public SinglyLinedNode<T> getNext() {
return next;
}
public void setNext(SinglyLinedNode<T> next) {
this.next = next;
}
}
@Data
public class SinglyLinkedList<T> {
/**
* 單鏈表的頭指針
*/
SinglyLinedNode<T> head;
/**
* 從尾部添加一個節點
*
* @param t t
*/
public void add(SinglyLinedNode<T> t) {
if (t == null) {
return;
}
if (head == null) {
head = t;
return;
}
SinglyLinedNode<T> couser = head;
while (couser.next != null) {
couser = couser.next;
}
couser.next = t;
}
/**
* 打印鏈表內容
*
* @return {@link String}
*/
public String getString() {
if (head == null) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
SinglyLinedNode<T> couser = head;
stringBuilder.append("鏈表:" + (couser.getData()==null?"null":couser.getData()));
while (couser.next != null) {
couser = couser.next;
stringBuilder.append("->" + (couser.getData()==null?"null":couser.getData()));
}
return stringBuilder.toString();
}
}
從指定的位置反轉單鏈表
/**
* 從第 index+1 的元素開始反轉,0反轉整個鏈表
*
* @param singlyLinkedList 單鏈表
* @param index 下標 >0
*/
static SinglyLinkedList reverseALinkedList(SinglyLinkedList singlyLinkedList, int index) {
//空、或者只有1個元素
if (singlyLinkedList.head == null || singlyLinkedList.head.next == null) {
return singlyLinkedList;
}
if (index <= 0) {
index = 0;
}
//反轉尾部的鏈表進行比較
SinglyLinedNode cursor = new SinglyLinedNode(null, singlyLinkedList.head);
int temp = 0;
//begin作為一個偽頭結點
SinglyLinedNode begin = new SinglyLinedNode(null, singlyLinkedList.head);
if (index == 0) {
singlyLinkedList.head = begin;
}
//mid作為截取隊列的的首個節點
SinglyLinedNode mid = null;
//end是需要進行頭插的節點
SinglyLinedNode end = null;
while (cursor.next != null) {
//遍歷鏈表
cursor = cursor.next;
temp++;
if (temp == index) {
begin = cursor;
}
if (temp - 1 == index) {
mid = cursor;
end = cursor.next;
}
//反轉半個鏈表,就地逆置法
if (temp > index && end != null) {
//將需要逆序的元素,直接作為頭結點的后繼節點
mid.next = end.next;
end.next = begin.next;
begin.next = end;
//保持遍歷的順序,將游標往后移動
cursor = mid;
//如果還有需要進行頭插的元素,則end指針需要往后移動一下
if (mid.next != null) {
end = mid.next;
}
}
}
if (index == 0) {
singlyLinkedList.head = begin.next;
}
SinglyLinkedList<Object> objectSinglyLinkedList = new SinglyLinkedList<>();
objectSinglyLinkedList.setHead(begin.next);
return objectSinglyLinkedList;
}
最終方法
/**
* 單鏈表結構判斷字符串是否是回文字符串
* 一般方法 復雜度為O(n2)
* 1. 如果字符串存儲在數組中,那么只需要判斷第一個和最后一個這么一一對應下去,判斷字符是否相同,還是比較簡單的。
* 2. 如果單鏈表中存儲也參照這種方法,那么可以定義兩個指針,一個初始指向頭部,一個初始指向尾部,后續依次一個向后指一個依次向前指。這樣也能判斷是否是回文字符串。但是對于單鏈表,查找前繼節點,需要遍歷鏈表,所以復雜度是O(n2)
* 復雜度為O(n)的方法
* 1. 如果使用單鏈表存儲,那么第一步需要找到鏈表的中間節點,這一步需要用到快慢指針
* 2. 第二步需要將單鏈表的后半部分進行反轉,單鏈表的反轉
*
* @author StoneYu
* @date 2022/09/25
*/
public class TestHuiWenZiFuChuan {
public static void main(String[] args) {
String testStr = "1";
SinglyLinkedList<Character> singlyLinkedList = transStringToLinkedList(testStr);
System.out.println(singlyLinkedList.getString());
//查找鏈表的中間節點的下標 快慢指針
SinglyLinedNode slow = singlyLinkedList.head;
SinglyLinedNode quick = singlyLinkedList.head;
int index = 1;
while (quick.next != null) {
slow = slow.next;
quick = quick.next;
if (quick.next == null) {
break;
}
quick = quick.next;
index++;
}
SinglyLinkedList singlyLinkedList1 = reverseALinkedList(singlyLinkedList, index);
System.out.println("中間位置為:"+index);
System.out.println("從中間反轉后原鏈表:" + singlyLinkedList.getString());
System.out.println("反轉后截取的鏈表:" + singlyLinkedList1.getString());
//定義兩個指針挨個比較
System.out.println("需要比較的節點數量中間數為"+(index%2==0?"偶數則-1":"奇數則不變")+":"+(index%2==0?index-1:index));
int needConpare=index%2==0?index-1:index;
int hasCompare=0;
SinglyLinedNode<Character> cursor1=new SinglyLinedNode(null,singlyLinkedList.head);
SinglyLinedNode<Character> cursor2=new SinglyLinedNode(null,singlyLinkedList1.head);
for (int i = 0; i <needConpare; i++) {
Character data1 = cursor1.next.data;
Character data = cursor2.next.data;
if (!data1.equals(data)){
System.out.println("\n\n判斷結果:"+testStr+"不是回文字符串");
return;
}
}
System.out.println("\n\n判斷結果:"+testStr+"是回文字符串");
}
/**
* 將字符串轉換為單鏈表
*
* @param targetStr 目標str
* @return {@link SinglyLinkedList}<{@link Character}>
*/
static SinglyLinkedList<Character> transStringToLinkedList(String targetStr) {
if (targetStr == null || targetStr.trim().equals("")) {
return null;
}
char[] chars = targetStr.toCharArray();
SinglyLinkedList<Character> characterSinglyLinkedList = new SinglyLinkedList<>();
for (Character aChar : chars) {
characterSinglyLinkedList.add(new SinglyLinedNode<>(aChar, null));
}
return characterSinglyLinkedList;
}
}
原文鏈接:https://blog.csdn.net/weixin_40979518/article/details/127033636
相關推薦
- 2022-07-11 Oracle使用dblink同步數據
- 2022-03-12 Android列表點擊事件定義的一些思考_Android
- 2022-06-06 uniApp實現滾動視圖點擊錨點跳轉、點擊左側分欄時右側對應內容置頂、左右分欄聯動、getSyste
- 2023-01-05 python?如何去除字符串中指定字符_python
- 2022-09-05 python使用pip成功導入庫后還是報錯的解決方法(針對vscode)_python
- 2022-09-16 C#?Socket數據接收的三種實現方式_C#教程
- 2023-01-28 Python進程間通訊與進程池超詳細講解_python
- 2022-06-17 C#中IEnumerable接口介紹并實現自定義集合_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支