【问题标题】:Given an array l1,l2,l3 . . . ln create a new array as follow: (l1+ln),(l2+l[n-1]), . . .(l[n/2]+l[n/2+1])给定一个数组 l1,l2,l3 。 . . ln 创建一个新数组,如下所示: (l1+ln),(l2+l[n-1]), . . .(l[n/2]+l[n/2+1])
【发布时间】:2020-10-04 05:34:31
【问题描述】:

所以我有以下问题:

给定一个数组 l1,l2,l3 。 . . ln,创建一个新数组如下: (l1+ln),(l2+l[n-1]), . . .(l[n/2]+l[n/2+1])。这个问题有以下规则和信息:

  • 原始列表只能阅读一次。
  • 列表是动态的,只有值和指向下一项的指针。
  • 新列表的类型必须与原始列表相同。
  • 不允许创建辅助列表来多次读取数据。

我已经尝试了很多次来解决它,虽然我已经接近解决方案,但结果仍然是错误的顺序。接下来我展示我当前的测试场景:

结构号 { 整数值; 否* 下一个; }; typedef No* Noptr; 主函数() { Noptr L = NULL; 插入列表(L,1); 插入列表(L,2); 插入列表(L,3); 插入列表(L,5); 插入列表(L,4); 插入列表(L,3); 插入列表(L,9); 插入列表(L,2); 插入列表(L,7); 插入列表(L,1); 插入列表(L,10); 插入列表(L,12); 插入列表(L,11); 插入列表(L,15); 插入列表(L,19); 插入列表(L,16); Noptr L4 = SumValues(L); 利斯塔(L4); 返回0; } Noptr SumValues(Noptr&L) { 如果(L == NULL){ 返回 L; } Noptr L1 = NULL; Noptr L2 = NULL; Noptr aux1 = L; 布尔偶数=假; 而(辅助1!= NULL) { 如果(!甚至) { InsertLista(L1,aux1->Value); } 别的 { InsertLista(L2,aux1->Value); } 偶数 = !偶数; aux1 = aux1->下一步; } L2 = InverterLista(L2); Noptr LReturn = NULL; 辅助1 = L1; Noptr aux2 = L2; 而(辅助1!= NULL){ InsertList(LReturn ,(aux1->Value+aux2->Value)); aux1 = aux1->下一步; aux2 = aux2->下一步; } 免费(L1); 免费(L2); 免费(辅助1); 免费(辅助2); 返回L返回; }

我期望数组:17, 21, 18, 16, 16, 13, 10, 9; 相反,我得到了:17, 18, 16, 10, 9, 13, 16, 21 为了更好地可视化,我创建了一个表格

 [00] [01] [02] [03] [04] [05] [06] [07] INDEX

 17   21   18   16   16   13   10   09  EXPECTED

 17   18   16   10   09   13   16   21  RESULT

我做错了什么?

【问题讨论】:

  • 无法复制。相反,我得到 11 个编译器错误。
  • 使用更小、更容易分析的测试用例。
  • 通过准备列表L1L2,你是不是违反了这个条件-不允许创建一个辅助列表来多次读取数据。 ?
  • 您似乎将此练习与其他练习混淆了。没有提到偶数和奇数元素,只是前半部分添加到后半部分的反面。
  • @H.S.该规则是为了防止创建类似的东西:Lcopy = Loriginal;尽可能多地阅读 Lcopy,因为它不是 Loriginal。对不起,如果它令人困惑。 Molbdnilo,代码只是我的尝试之一,因为列表可以包含任意数量的元素,只要它有偶数个,我认为将它们分成 2 个子列表会有所帮助。

标签: c++ algorithm


【解决方案1】:

算法:

  1. 反转原始列表的前半部分。
  2. 遍历前半部分和后半部分列表:
    • 注意列表的大小:
      • 如果原始列表大小为奇数,则中间节点值将是新列表的最后一个节点值。
      • 如果原始列表大小是偶数,则n/2th 节点和n/2 + 1th 节点值的总和将是新列表的最后一个节点值。请注意,n/2th 节点是反向列表的第一个节点,n/2 + 1th 节点是后半列表的第一个节点。
    • 添加两个列表节点的值并将此值分配给新的列表节点。移至两个列表中的下一个节点。
    • 将新列表节点的每个节点都添加到新列表的头部。
  3. 重复步骤 2,直到任一列表指针到达 nullptr
  4. 将原始列表重置为其原始形式(再次反转前半部分)。

实现:
(不是纯面向对象的实现但足够理解)

#include <iostream>
#include <cstdlib>

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
    ~ListNode(){/*take care of deallocation*/}
};

struct ListNode * getNode(int x) {
    struct ListNode *temp = new ListNode(x);
    if (temp == nullptr) {
        exit (EXIT_FAILURE);
    }

    return temp;
}

void insert(int d, struct ListNode ** head) {
    struct ListNode *temp = getNode(d);

    if (temp == nullptr) {
        exit (EXIT_FAILURE);
    }

    struct ListNode **curr = head;
    while (*curr) {
        curr = &((*curr)->next);
    }

    *curr = temp;
}

// Algorithm implementation
struct ListNode * sumValues(struct ListNode *head){
    int odd = 0;
    struct ListNode *slowPtr = head;
    struct ListNode *fastPtr = head;
    struct ListNode *newList = nullptr;
    struct ListNode *prev = nullptr;

    // Reverse first half of original list
    while (fastPtr) {
        fastPtr = fastPtr->next;
        if (!fastPtr) {
            odd = 1;
            break;
        }
        fastPtr = fastPtr->next;
        struct ListNode *curr = slowPtr->next;
        slowPtr->next = prev;
        prev = slowPtr;
        slowPtr = curr;
    }

    struct ListNode *L1 = prev;
    struct ListNode *L2 = nullptr;
    L2 = slowPtr;

    // The middle node of original list will be last node of new list if orignal list has odd number of nodes
    if (odd) {
        L2 = L2->next;
        newList = getNode(slowPtr->val);
    }

    // Traverse both first half (reversed) and second half of original list and prepare new list
    while (L2) {
        struct ListNode *tmp = getNode(L1->val + L2->val);
        tmp->next = newList;
        newList = tmp;
        L2 = L2->next;
        L1 = L1->next;
    }

    // Reset the original list
    struct ListNode *tmp = prev;
    prev = slowPtr;
    while (tmp) {
        struct ListNode *curr = tmp->next;
        tmp->next = prev;
        prev = tmp;
        tmp = curr;
    }

    return newList;
}

void printList(struct ListNode * newList, struct ListNode *origList) {
    struct ListNode *x = origList;
    std::cout << "\nPrint lists\n";
    std::cout << "Original list : ";
    while (x) {
        std::cout << x->val << " ";
        x = x->next;
    }

    std::cout << "\n"; 
    x = newList;
    std::cout << "Sum List : ";
    while (x) {
        std::cout << x->val << " ";
        x = x->next;
    }

    std::cout << "\n"; 
}

// Driver code
int main() {
    struct ListNode *head = nullptr;
    struct ListNode *newList = nullptr;

    insert (1, &head);
    // list =>  1 -> null
    newList = sumValues(head);
    printList(newList, head);

    insert (2, &head);
    // list =>  1 -> 2 -> null
    newList = sumValues(head);
    printList(newList, head);

    insert (3, &head);
    // list => 1 -> 2 -> 3 -> null 
    newList = sumValues(head);
    printList(newList, head);

    insert (4, &head);
    // list =>  1 -> 2 -> 3 -> 4 -> null
    newList = sumValues(head);
    printList(newList, head);

    insert (5, &head);
    // list =>  1 -> 2 -> 3 -> 4 -> 5 -> null
    newList = sumValues(head);
    printList(newList, head);

    insert (4, &head);
    // list =>  1 -> 2 -> 3 -> 4 -> 5 -> 4 -> null
    newList = sumValues(head);
    printList(newList, head);

    insert (2, &head);
    // list =>  1 -> 2 -> 3 -> 4 -> 5 -> 4 -> 2 -> null
    newList = sumValues(head);
    printList(newList, head);

    insert (4, &head);
    // list =>  1 -> 2 -> 3 -> 4 -> 5 -> 4 -> 2 -> 4 -> null
    newList = sumValues(head);
    printList(newList, head);

    insert (1, &head);
    // list =>  1 -> 2 -> 3 -> 4 -> 5 -> 4 -> 2 -> 4 -> 1 -> null
    newList = sumValues(head);
    printList(newList, head);

    // Make sure to deallocate both the list

    return 0;
}

输出:

# ./a.out

Print lists
Original list : 1 
Sum List : 1 

Print lists
Original list : 1 2 
Sum List : 3 

Print lists
Original list : 1 2 3 
Sum List : 4 2 

Print lists
Original list : 1 2 3 4 
Sum List : 5 5 

Print lists
Original list : 1 2 3 4 5 
Sum List : 6 6 3 

Print lists
Original list : 1 2 3 4 5 4 
Sum List : 5 7 7 

Print lists
Original list : 1 2 3 4 5 4 2 
Sum List : 3 6 8 4 

Print lists
Original list : 1 2 3 4 5 4 2 4 
Sum List : 5 4 7 9 

Print lists
Original list : 1 2 3 4 5 4 2 4 1 
Sum List : 2 6 5 8 5 

如果不允许操作原始列表,那么您可以使用堆栈来准备总和列表。 使用堆栈的算法

  1. 将前半部分原始列表推入堆栈。
  2. 遍历原始列表的后半部分:
    • 注意列表的大小:
      • 如果原始列表大小为奇数,则中间节点值将是新列表的最后一个节点值。
      • 如果原始列表大小是偶数,则n/2th 节点和n/2 + 1th 节点值的总和将是新列表的最后一个节点值。请注意,n/2th 节点是堆栈的第一个节点,n/2 + 1th 节点是后半列表的第一个节点。
    • 从堆栈中选择顶部值并与后半列表的当前节点的值相加并分配给新的列表节点。从堆栈中弹出值并将后半部分的指针移动到其next
    • 将新列表节点的每个节点都添加到新列表的头部。
  3. 重复步骤 2,直到堆栈为空或后半遍历指针到达 nullptr

使用双端队列的算法

  1. 采用双向队列。
  2. 遍历整个链表,将链表的元素推到队列后面。
  3. 从队列的前后弹出元素,添加它们并将此值分配给要添加到新列表尾部的节点的值。
  4. 重复第 3 步,直到队列为空。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 2020-05-19
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    相关资源
    最近更新 更多