【c++复健】双指针(第二弹)
还是在乐扣刷双指针题目。
这次第一题是字符串反转,没什么要求,就是不能新建数组,那就直接双指针对换位置。
class Solution {
public:
void reverseString(vector<char>& s) {
int len = s.size();
int i = 0;
int j = len - 1;
char temp;
while(i<j){
temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
};
第二题稍微复杂点,也是字符串反转,但是只反转单词,空格保留,而且单词顺序保留。
这道题也用双指针做,但是我这里想的复杂了点。我是找出每一个单词,然后对单词内部进行一次反转,然后把两个指针都定位到下一个单词的第一个字母,继续往右挪动。
class Solution {
public:
string reverseWords(string s) {
int len = s.size();
string *answer = new string[len];
int i,j;
i = 0;
j = 0;
int temp;
int dealed = 0;
while(dealed < len){
if(s[j] != ' ' && j != len-1){
j++;
}
else if(s[j] == ' ' && j != len-1){
temp = j;
dealed += j - i + 1;
j--;
while(i<j){
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
i++;
j--;
}
i = temp+1;
j = temp+1;
}
else{
dealed += j - i + 1;
while(i<j){
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
i++;
j--;
}
}
}
return s;
}
};
这个方法是“原地解法”,在部分string不能修改的语言中无法使用,所以其他语言推荐建个新数组,就不用再原字符串中搞位运算,而是直接放到新字符串中。
第三题是链表双指针,但是我用的单指针,,
题目如下:
直接上代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
int len = 1;
ListNode *answer = head;
while(head->next != NULL){
head = head->next;
len++;
}
int middle = len / 2;
if(len = middle * 2){
middle = middle + 1;
}
for(int i=1;i<middle;i++){
answer = answer->next;
}
return answer;
}
};
这个题实际上是典型的快慢指针题目,快指针一次走两步,慢指针一次走一步。
快指针摸到尾部的时候,慢指针刚好到一半。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *fast,*slow;
fast = head;
slow = head;
while(slow->next != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
};
今天最后一题:
和上面一题一样,我采用了快慢指针,但是如果删除最后一个和第一个的节点的话,可能会有问题。所以我写的比较长。效率一般,但是我看官方好像好的解法也不多,主要是他没按照他这个题目要求来,要求只能遍历一遍来着。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *slow,*fast,*start;
slow = head;
fast = head;
int i = 0;
int j = 1;
if(head->next == NULL){
return NULL;
}
else{
while(slow->next != NULL && fast->next != NULL){
if(i >= n){
fast = fast->next;
slow = slow->next;
j++;
}
else{
fast = fast->next;
i++;
j++;
}
}
}
if(n==1){
slow->next = NULL;
return head;
}
else if(j == n){
if(n == 1){
head->next = NULL;
return head;
}
else{
return head->next;
}
}else{
slow->next = slow->next->next;
return head;
}
}
};