タイトルの説明:リンクリストが与えられた場合、それがパリンドロームリンクリストであるかどうかを判断できます。パリンドロームリンクリストの場合はtrueを返し、そうでない場合はfalseを返します。
たとえば、1 2 3 5 3 2 1
合計1 2 3 5 5 3 2 1
はパリンドロームリンクリストです。
制限条件:制御時間の複雑さはO(n)、スペース複雑さはO(1)であり、
問題を解決するためのアイデア:
STEP1:それは回文リンクリストであるか否かを決定するためには、前半(オーダー)の要素と後半(逆順)がすべて同じであるかどうかを判断する必要があるため、我々は最初のリンクリストを見つける必要があります中間ノードは、
。ここでこれは、リンクされたリストの1.5トラバーサルを必要とする一般的な方法で、ある長さのサイズを取得するために一度ノードを横断して、中間ノードを取得するために最初からサイズ/ 2ノードを通過すると考えることがあり、それが使用されますのダブルポインター-速いポインターと遅いポインターこの方法では、リンクリストを0.5回トラバースするだけで済みます。原則として、高速ポインタは毎回2ステップ、低速ポインタは毎回1ステップであるため、高速ポインタが終点(NULL)に達すると、低速ポインタはリンクリストの後半を指すだけです。
メソッド1の最初の要素
step2:この時点で、リンクリストの後半を反転することを考えて、反転したリンクリストの前半と後半を比較する方が簡単なので、2番目のステップはリンクリストを反転することです。;のみnow、pre、aft
、3つのノードが必要とされる、リンクされたリストを逆に
STEP3:順番にトラバース2つのリンクリスト、及び対応する位置に二つの要素が等しいかどうかを比較します。
コード:
bool isPalindrome(ListNode* head) {
//O(n)、O(1)
ListNode* slow = head, *fast = head;
while (fast) //find mid node
{
slow = slow->next;
fast = fast->next ? fast->next->next: fast->next;
}
ListNode *prev = nullptr;
while (slow) //reverse
{
ListNode* temp = slow->next;
slow->next = prev;
prev = slow;
slow = temp;
}
while (head && prev) //check
{
if (head->val != prev->val){
return false;
}
head = head->next;
prev = prev->next;
}
return true;
}
方法2:
使用それは回文リストであるかどうかを判断するための再帰的方法;
STEP2:
1度の繰り返しを探す:反復サブ問題を見つける。
ここでは、おそらく得ることができます再帰関数の一般的な外観は次のとおり
void check(ListNode *head1,int l,ListNode *&head2,int r,flag) //判断链表[l~r]是否为回文链表
です。スタックはfirst-in-last-outであるため、head1はヘッドノードへのポインタです。再帰が5に達すると、ゆっくりと再帰に戻り
、中央から前に向かって歩きます。中央から後ろに向かって歩く場合も同様です。ポインタ、使用する必要があります見積もり&head2
head1とhead2が対応する比較位置になるように、値を段階的に増やして逆方向に戻しましょう。
2°変化を見つける:変化の量はl,r,head2,flag
l,r代表check函数比较链表第i和第r个的元素,flag用于标志是否为回文链表,初始为true,如果出现两比较值不相等,则置为false
3°境界を見つける:問題を段階的に減らします。最後l>=r
に、サブ問題が最小スケールに達したことを意味します(l == rは単一の要素を指していることを意味し、比較する必要はありません。l> rは制限を超えていることを意味します)return
。
その場合、再帰関数全体は次の形式になります。
void check(ListNode *head1, int l, ListNode *&head2, int r, bool &flag) //判断链表[l~r]是否为回文 (注意head2是变化的 它要一次次往后走 一定要引用)
{
//边界条件
if (l >= r)
{
return;
}
//将问题规模缩小
if (r - l >= 2)
{
check(head1->next, l + 1, head2, r - 1, flag);
}
//比较对应位置节点值
int a = head1->val, b = head2->val;
if (a != b)
{
flag = false;
}
//head2指向下一个结点,此时该函数完成返回其调用函数时,head1也指向前一个结点,这样又能比较两个数是否相等了
head2 = head2->next;
}
step3:判定フラグフラグを返します。
void check(ListNode *head1, int l, ListNode *&head2, int r, bool &flag) //判断链表[l~r]是否为回文 (注意head2是变化的 它要一次次往后走 一定要引用)
{
//边界条件
if (l >= r)
{
return;
}
//将问题规模缩小
if (r - l >= 2)
{
check(head1->next, l + 1, head2, r - 1, flag);
}
//比较对应位置节点值
int a = head1->val, b = head2->val;
if (a != b)
{
flag = false;
}
//head2指向下一个结点,此时该函数完成返回其调用函数时,head1也指向前一个结点,这样又能比较两个数是否相等了
head2 = head2->next;
}
bool isPalindrome(ListNode *head)
{
//如果有1个及以下的元素,返回true
if (head == nullptr || head->next == nullptr)
{
return true;
}
//利用快慢指针求链表个数和中间节点
int size = 0;
ListNode *slow = head, *fast = head, *mid_point = nullptr;
while (fast)
{
//find mid node
size++;
slow = slow->next;
fast = fast->next ? fast->next->next : fast->next;
}
//设置指向中间节点的指针
mid_point = slow;
while (slow)
{
size++;
slow = slow->next;
}
bool flag = true;
check(head, 1, mid_point, size, flag);
return flag;
}