给出了链表
的以下定义typedef struct elemento {
int inf;
struct elemento *next;
} lista;
我正在尝试创建一个函数
lista * SeekAndDestroy(lista * p,int k);
给定列表* p和正整数k(在列表上搜索),第一个连续元素序列的总和恰好是k,并从列表中消除这些元素。
我的尝试:
lista *SeekAndDestroy(lista *p, int k) {
lista *a, *nuovo;
int x = 0;
a = (lista *)malloc(sizeof(lista));
a->inf = p->inf;
nuovo = a;
p = p->next;
while (p != NULL) {
if (p->next != NULL) {
if ((p->inf + p->next->inf) == k) {
if (x != 1) {
p = p->next->next;
x = 1;
continue;
}
}
}
nuovo->next = (lista *)malloc(sizeof(lista));
nuovo = nuovo->next;
nuovo->inf = p->inf;
p = p->next;
}
nuovo->next = NULL;
return a;
}
我的解决方案有两个主要问题:
1)最多删除两个连续元素而不是更多
2)如果要删除的项目是前两项,则该功能不起作用
我怎么解决这个问题?感谢
答案 0 :(得分:1)
假设您的数字都是非负数,那么您可以使用更高效的算法。您只需在列表中运行两个指针ptrA
和ptrB
,保持包含元素的总和。
如果总和不是你需要什么,你可以做两件事之一。首先,如果当前总和小于所需数量,则通过推进ptrB
将下一个元素带入数组。
如果您当前的总和多超过您的需要,您可以通过推进ptrA
来取出您范围内的第一个元素。当然,这两种操作都应该调整当前的范围总和。这里有一个边缘案例,如果目前只有一个项目,你就不想这样做。
不言而喻,如果当前范围总和等于您所需的范围,您只需删除该范围并退出。
就伪代码而言,它将类似于:
def delExact(list, desiredSum):
# Check non-empty and start range.
if list is empty:
return
ptrA = list.first
ptrB = ptrA
rangeSum = ptrA.value
# Continue until match found
while rangeSum is not equal to desiredSum:
# Select add-another or remove-first.
if ptrA == ptrB, or rangeSum < desiredSum:
# Need to bring another in, returning if list exhausted.
ptrB = ptrB.next
if ptrB == null:
return
rangeSum = rangeSum + ptrB.value
else:
# Need to remove one.
rangeSum = rangeSum - ptrA.value
ptrA = ptrA.next
# If we exit the loop, we've found a sum match.
# Hence we need to delete ptrA through ptrB inclusive.
然而,如果允许使用负数,那么双指针方法就会崩溃,因为你实际上并不知道后来的元素会有什么影响。
在这种情况下,你基本上必须对所有可能性进行详尽的搜索,这基本上归结为:
for each element in list:
for each possible segment from that element on:
check and act on summed data
这实际上更像是一个英语代表,这种野兽的伪代码将是:
def delExact(list, desiredSum):
# For each list element.
ptrA = list.first
while ptrA is not null:
# For each possible segment starting at that element.
segmentSum = 0
ptrB = ptrA
while ptrB is not null:
add ptrB.value to segmentSum
# Delete segment if sum matches, then return.
if segmentSum is equal to desiredSum:
# Here we delete from ptrA through ptrB inclusive.
return
# Otherwise, keep adding elements to segment.
ptrB = ptrB.next
# No matching segment, move on to next element.
ptrA = ptrA.next
# No matching segment at any element, just return.
使用 这些算法将解决您只删除两个元素的问题。
在列表开头删除的问题是简单地识别该事实(ptrA == list.first
)并确保在这种情况下调整first
指针。这是链表处理中的标准边缘情况,可以实现为:
def deleteRangeInclusive(list, ptrA, ptrB):
# Adjust list to remove ptrA/ptrB segment,
# allowing for possibility ptrA may be the head.
if ptrA == list.first:
list.first = ptrB.next
else:
beforeA = list.first
while beforeA.next != ptrA:
beforeA = beforeA.next
beforeA.next = ptrB.next
# Now we can safely remove the ptrA-ptrB segment.
while ptrA != ptrB:
tempA = ptrA
ptrA = ptrA.next
delete element tempA
delete element ptrB
答案 1 :(得分:1)
现在,让我们忘记链表和指针和东西。说,我们必须解决给定数组的问题。我们可以这样做吗?当然!
for (int i = 0; i < array.length; ++i) {
for (int j = i; j < array.length; ++j) {
int sum = getRangeSum(array, i, j);
if (sum != k) continue;
// construct new array and return
}
}
此代码可以进一步优化,但现在让它保持简单。因此,在链表中,可以使用类似的方法。删除部分也很简单。您可以保留一个变量来跟踪 i 的上一个节点。我们称之为 iParent 。现在,我们可以将[i,j]段删除为iParent->next = j->next
。
显然,您需要考虑一些极端情况,例如,如果找不到这样的段,或者段是否从链表的开头开始等。
答案 2 :(得分:1)
这是我写的一个函数,用于解决您面临的两个问题以及任何其他边界条件:
list* Seek_Destroy(list* head, int target){
if(head == NULL)
return NULL;
list* temp = head;
bool find_complete = false;
list *prev = temp;
//Loop for iterating until list is complete or target sum is found.
while( !find_complete){
//Create a pointer for loop calculations
list* sum_loop = temp;
//Initialize sum to 0
int sum =0;
//Loop for checking whether the sum is equal to the target
while(sum <= target && sum_loop->next!= NULL){
//Keep adding the sum
sum += sum_loop->inf;
if(sum == target){
//Set the flag for exiting outer loop
find_complete = true;
//Test whether head of the list is included in the sum
if (temp == head){
//Make head point to the struct after the last element included in the sum loop
head = sum_loop->next;
//Delete and free memory
while(temp!= sum_loop){
list* del = temp;
temp = temp->next;
free(del);
}
}else {
//Set the next pointer of previous element of the list to point after the last element included in the sum loop
prev->next= sum_loop->next;
//Delete and free memory
while(temp!= sum_loop){
list* del = temp;
temp = temp->next;
free(del);
}
}
break;
}
//Increment the pointer for the sum calculation
sum_loop = sum_loop->next;
}
prev = temp;
//Make temp point to next element in the list
temp = temp->next;
//IF entire list is traversed set the flag to true
if (temp ==NULL){
find_complete = true;
}
}
return head;
}
答案 3 :(得分:0)
我这样解决了:
Lista *Distruggi(Lista *p, int k) {
Lista *n = NULL, *nuova = NULL;
int z = 0;
for (Lista *i = p; i != NULL && z != 1; i = i->next) {
for (Lista *j = i; j != NULL; j = j->next) {
int sum = somma(i, j);
if (sum != k) continue;
n = (Lista *)malloc(sizeof(Lista));
n->inf = p->inf;
p = p->next;
nuova = n;
while (p != i) {
nuova->next = (Lista *)malloc(sizeof(Lista));
nuova = nuova->next;
nuova->inf = p->inf;
p = p->next;
}
while (j != NULL) {
nuova->next = (Lista *)malloc(sizeof(Lista));
nuova = nuova->next;
nuova->inf = j->inf;
j = j->next;
}
z = 1;
break;
}
}
if (z == 0) return p;//NO CHANGE
else {//CHANGE
nuova->next = NULL;
return n;
}
}