328
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(head == NULL){
return head;
}
ListNode* odd = head;//遍历奇数节点
ListNode* oddtail = head;//记录奇数节点的尾节点
ListNode* eve = head->next;//记录偶数节点
ListNode* eveHead = head->next;//记录偶数的头结点
while(eve != NULL && odd != NULL){
odd->next = eve->next;
odd = odd->next;
if(odd != NULL){//如果奇节点为NULL,无需为偶节点赋值
eve->next = odd->next;
eve = eve->next;
oddtail = odd;//如果当前的odd节点不是NULL,表明他是尾节点
}
}
oddtail->next = eveHead;
return head;
}
};
思路
奇数节点可以通过相邻偶数节点的next获取下一个奇数节点,同理,偶数节点也可以通过相邻的奇数节点的next获取下一个偶数节点
解法
- 通过奇数节点获取偶数节点,通过偶数节点获取奇数节点,循环连接
- 每次连接前判断是否为NULL,如果是,停止连接。
725
/**
* 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:
vector<ListNode*> splitListToParts(ListNode* head, int k) {
vector<ListNode*> ans(k);
if(head == NULL){return ans;}//判空
//计算链表长度
int len = 0;
ListNode* m_head = head;
while(m_head != NULL){
++len;
m_head = m_head->next;
}
m_head = head;
//计算ans中,分割区域的长度
int x = len/k;//每个区域相等时候的长度
int y = len%k;//剩下的长度,分配给靠前的区域
vector<int> subLen(k,x);
for(int i = 0; i < y; ++i){
subLen[i] += 1;//前面的每个区域每个分到1的长度
}
ListNode* tmp = NULL;
for(int i = 0; i < k && subLen[i] != 0; ++i){//分割每一个区间
ans[i] = m_head;
for(int count = 0; count < subLen[i] && m_head != NULL; ++count){//获取下一个头结点
if(count == subLen[i]-1){
tmp = m_head;//获取当前区间尾节点
}
m_head = m_head->next;//获取下一个节点
}
tmp->next = NULL;//截断当前区间的尾节点,和下一个区间的头结点
}
return ans;
}
};
思路
本题思路比较清晰,唯一的难点是如何分配k个区域的长度,以及如何分割区间。
为了保证每个区域长度尽可能相等,那么我们不妨假设相等,因此,每个区间长度为len/k
but,整除是会忽略余数,需要重新分配余数,否则会缺少节点
因为余数一定小于k,所以我们可以将余数平均分配给前面的区域,每个区域获得1,保证前面区域长度大于等于后面区域长度
解法
- 计算每个区域的长度。
- 依据区域长度,分割链表上个区间的尾节点和下个区间的头结点,存入ans。
817
/**
* 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 {
int hash[10001];//将链表改为线性表,并且存储每个节点的在链表中的“下标”
vector<int> index;//存储nums中的数,在链表的位置
public:
int numComponents(ListNode* head, vector<int>& nums) {
int len = 0;
ListNode* m_head = head;
memset(hash,-1,sizeof(hash));
while(m_head != 0){//链表变成线性表,方便nums中的元素查找在链表中的位置
++len;
hash[m_head->val] = len-1;//记录val的下标,并且下标为len-1
m_head = m_head->next;
}
for(int i = 0; i < nums.size(); ++i){//根据nums中val的映射,通过hash快速找到对应的val所在链表的下标
index.emplace_back(hash[nums[i]]);//将nums中元素在链表中对应的下标存入index中
}
sort(index.begin(),index.end());//对index排序
int count = 1, preidx = index[0];
for(int i = 1; i < index.size(); ++i){//遍历index
if(index[i]-preidx != 1){//当前元素在链表中的index和前一个元素在链表中的index只差1,表示该两元素在链表中相邻
++count;
}
preidx = index[i];
}
return count;
}
};
思路
本题可转化为nums中的元素依照是否在链表中相邻划分,返回划分区域的个数。
相邻与否,主要看nums中元素在链表中的位置。如果得到nums中所有元素在链表中的位置的数组,index。对index排序,我们就能通过每个元素的位置是否和其前一个元素的位置相同来判断相邻区域的个数
eg:
list: 0 3 2 4 1
nums 3 0 2 1
index 在list[1]位 在list[0]位 在list[2] 在list[3]
index 1 0 2 3
对index排序
0 1 2 3
因为在index数组中0,1,2相邻;3单独一个位置,所以划分区域为2
解法
- 将链表转化为线性表,每个位置的值对应其在链表的位置
- 查找nums的每个元素在链表中的位置,并按照位置顺序生成数组index
- 判断index每个元素是否相邻
622
class MyCircularQueue {
#define ElementType int
public:
MyCircularQueue(int k) {
curNum = 0, maxNum = k;
ListNode* newNode = new ListNode;//获得新节点
newNode->next = NULL;
head = tail = newNode;
for(int i = 0; i < k-1; ++i){
newNode = new ListNode;
newNode->next = NULL;
tail->next = newNode;
tail = tail->next;
}
tail->next = head;//形成环形链表
tail = head;//当前没有元素的存在
}
bool enQueue(int value) {
if(isFull()){//满了
return false;
}
if(isEmpty()){
tail->val = value;
}else{//tail永远指向他要添加的节点
tail = tail->next;
tail->val = value;
}
++curNum;
return true;
}
bool deQueue() {
if(isEmpty()){//空的
return false;
}
if(curNum == 1){//保持head,tail相对位置
head = head->next;
tail = head;
}else{
head = head->next;
}
--curNum;
return true;
}
int Front() {
if(isEmpty()){//空的
return -1;
}
return head->val;
}
int Rear() {
if(isEmpty()){//空的
return -1;
}
return tail->val;
}
bool isEmpty() {
return !curNum;
}
bool isFull() {
return !(maxNum-curNum);
}
private:
ListNode* head;
ListNode* tail;
int curNum;
int maxNum;
};
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue* obj = new MyCircularQueue(k);
* bool param_1 = obj->enQueue(value);
* bool param_2 = obj->deQueue();
* int param_3 = obj->Front();
* int param_4 = obj->Rear();
* bool param_5 = obj->isEmpty();
* bool param_6 = obj->isFull();
*/
思路
当做联系链表实现循环队列了,练习基本功。
需要注意的就是,头指针和尾指针在enQueue和deQueue时候的特殊情况,没有元素;只有一个元素。
enQueue,如果当前没有元素,head和tail指在同一个节点,如果tail移动,在下一个元素插入,那么会导致head指向的节点是空数据;所以在没有元素的时候,应该不移动tail指针,在tail所指向的位置填充数据。保证指针指向的节点就是数据要填充的节点,在其他情况下,先移动tail到next节点,然后赋值即可。
deQueue,如果当前只有一个元素,移动head到next节点,**因为保证了指针指向的节点就是数据填充过的节点,因此,只有一个元素时,head和tail会重合。**如果继续移动head到next,会导致不存在元素的时候head移动到tail前面,因此,需要同时移动head,tail,保证两者的相对位置(其他操作也行)。