Day4 59螺旋矩阵2, 203移除链表元素(带头结点法),707设计链表(单链表版本)

59 螺旋矩阵

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例 1:

Day4 59螺旋矩阵2, 203移除链表元素(带头结点法),707设计链表(单链表版本)_第1张图片

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

        要画出一个螺旋形状的矩阵,看着就脑壳痛,完全没有想法。这里我们要想到顺时针画矩阵的过程,填充上行从左到右,填充右列从上到下,填充下行从左到右,填充左列从下到上 ,这样像海螺一样,一圈一圈的处理。

Day4 59螺旋矩阵2, 203移除链表元素(带头结点法),707设计链表(单链表版本)_第2张图片

        这里的每个颜色代表着一条边,所要遍历的规则也是不一样的,尤其是拐角这里,挺难处理的。我们设想大循环套小循环,一个一圈大循环套上四个边的小循环,这样就能够遍历。

        注意一点,每个边的遍历到底怎么取边呢?一整个边?还是左开右闭左闭右开之类的?都可以!但是要确保全程要有一个规则--循环不变量原则,这里我的处理方式统一的左闭右开。

        首先定义一个二维数组存放所要return的答案,定义一个loop来表示每个圈循环几次,也就是大的循环变量,startx和starty表示的是每一圈最开始循环的时候的起点,offset是来计算每次小循环时的边长,count用来记录放入ans中的数值,每次加1。此时用while语句进入大循环,循环次数其实就是n/2(圈数),此时,进入四条边的赋值循环,i代表行,j代表列,首先j从starty开始遍历,遍历到本行的倒数第二个元素,i也是同理,第三次j要遍历到starty处,i也是同理,每次都要让count++,每次while都要让start++,loop--。最后处理一下比较特殊的情况,就是如果n是个奇数,最后循环很多圈以后,中间会剩下一个元素,让这个元素等于n²即可,本题代码如下,时间复杂度为O(n²)。

class Solution {
public:
    vector> generateMatrix(int n) {
        vector>ans(n,vector(n,0));
        int startx=0,starty=0,offset=1,count=1;
        int i,j;
        int loop = n/2;
        while(loop)
        {
            for(j=starty;jstarty;j--)
                ans[i][j]=count++;
            for(;i>startx;i--)
                ans[i][j]=count++;
            startx++;
            starty++;
            offset++;
            loop--;
        }
        if(n%2==1)
            ans[n/2][n/2]=n*n;
        return ans;
    }
};

        当然,本题代码还可以继续优化,不需要两个start,直接用offset来处理,因为这三个量其实是有一定的关系的,简单计算一下,其他的同上。

class Solution {
public:
    vector> generateMatrix(int n) {
    vector>ans(n,vector(n,0));
    int i,j;
    int offset = 0;
    int loop = n/2;
    int count =1;
    while(loop)
    {
        for(j=offset;joffset;j--)
            ans[i][j]=count++;
        for(;i>offset;i--)
            ans[i][j]=count++;
        offset++;
        loop--;
        
    }
    if(n%2==1)
        ans[n/2][n/2]=n*n;
    return ans;
    }
};

        这样就完成了螺旋矩阵的设计,本题主要要注意以下几点:循环不变量,循环条件,没有什么算法,只是一个特殊的案例而已,暴力求解。

203移除链表元素(带头结点法)

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

Day4 59螺旋矩阵2, 203移除链表元素(带头结点法),707设计链表(单链表版本)_第3张图片

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

        终于进入了新的篇章---链表。移除元素的原理,让这个元素的上一个节点连接到这个元素的下一个结点上,然后再delete掉这个删除的结点即可,其实就是让结点next指针直接指向下一个结点,这里我们设计一个虚拟头结点,对后面的操作会比较方便。本题比较简单,时间复杂度为O(n),代码如下:

/**
 * 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* removeElements(ListNode* head, int val) {
        ListNode*dummyHead=new ListNode(0, head);
        ListNode*current=dummyHead;
        while(current->next!=nullptr)
        {
            if(current->next->val==val)
            {
                ListNode*tmp = current->next;
                current->next=current->next->next;
                delete(tmp);
            }
            else
            {
                current = current->next;
            }
        }
        head = dummyHead->next;
        delete dummyHead;
        dummyHead = nullptr;
        return head;

    }
};

        要注意的几点就是:不能直接用虚拟头结点进行后面的操作,都则最后要返回的时候就找不到真正的head了,所以建立一个current;其次在寻找val时,也要创建一个tmp来指向current,是为了释放删除元素的空间;最后不要忘记把虚拟头结点dummyhead也给释放了,同时释放内存以后最好让他指向nullptr。

707设计链表(单链表版本)

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。

如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

         本题涵盖了链表设计的大部分操作,首先一定要先创建一个链表,一般都要有值,下一个地址的指针,和一个构造函数列表,代码如下:

struct LinkedNode{
        int val;
        LinkedNode*next;
        LinkedNode(int val):val(val),next(nullptr){}
    };

        之后时这个类的构造函数,我们采用虚拟头结点的话,需要定义一个虚拟头结点,同时,因为后面还要进行一些函数的操作,所以要设定一个链表长度size,代码如下:

MyLinkedList() {
        dummyhead = new LinkedNode(0); 
        size = 0;
    }

private:
    int size;
    LinkedNode* dummyhead;

        接下来就是各种内置函数的实现了:

        首先是获取下标index结点的值,一定要先判断下标是否有效,如果下标小于0或者大于size-1,均为非法下标,此时return-1,其他的时候,定义一个cur指向dummyhead的下一个元素,遍历index,一直往下指,直到最后找到index元素,返回它的value,代码如下:

 int get(int index) {
        if(index<0||index>(size-1))
            return -1;
        LinkedNode*cur=dummyhead->next;
        while(index)
        {
            cur=cur->next;
            index--;
        }
        return cur->val;
    }

        头插法:先要new出来一个要插入的元素,因为我们有虚拟头结点,所以让新元素的next指向dummydhead的next,再让dummy的next指向新元素,最后别忘了要让size++。

void addAtHead(int val) {
        LinkedNode*NewNode=new LinkedNode(val);
        NewNode->next=dummyhead->next;
        dummyhead->next=NewNode;
        size++;
    }

        尾插法:与头插法类似,但是要先找到尾巴,什么时候能遍历到尾巴呢,就是cur的next为空指针的时候,找到最后一个cur让其指向新元素即可。

 void addAtTail(int val) {
        LinkedNode*NewNode=new LinkedNode(val);
        LinkedNode*cur=dummyhead;
        while(cur->next!=nullptr)
        {
            cur=cur->next;
        }
        cur->next=NewNode;
        size++;
    }

        按照下标增加元素:判断如果index大于size了,那么就直接return,如果index=0,那么采用头插法函数,如果index=size,那就采用尾差法函数,对于其余的情况,只好正常的来设计了,既然要在index的前一个位置插入元素,那么就要找到cur和cur的next,在这两个中间插入元素才行,不要忘记size++。

 void addAtIndex(int index, int val) {
        LinkedNode*NewNode=new LinkedNode(val);
        LinkedNode*cur=dummyhead;
        if(index>size)
            return;
        if(index==0)
            addAtHead(val);
        else if(index==size)
            addAtTail(val);
        else
        {
            while(index)
        {
            cur=cur->next;
            index--;
        }
        NewNode->next=cur->next;
        cur->next=NewNode;
        size++;
        }
    }

        删除指定元素:先要判断index是否非法,之后正常删除即可,同上一题,注意最后delete以后还要将指针设置成nullptr,还有别忘了size--。

 void deleteAtIndex(int index) {
        if(index<0||index>=size)
            return;
        LinkedNode*cur=dummyhead;
        while(index)
        {
            cur=cur->next;
            index--;
        }
        LinkedNode*tmp=cur->next;
        cur->next=cur->next->next;
        delete tmp;
        tmp=nullptr;
        size--;
    }

        至此设计完成,本题的完整代码如下所示:

class MyLinkedList {
public:
    struct LinkedNode{
        int val;
        LinkedNode*next;
        LinkedNode(int val):val(val),next(nullptr){}
    };
    MyLinkedList() {
        dummyhead = new LinkedNode(0); 
        size = 0;
    }
    
    int get(int index) {
        if(index<0||index>(size-1))
            return -1;
        LinkedNode*cur=dummyhead->next;
        while(index)
        {
            cur=cur->next;
            index--;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkedNode*NewNode=new LinkedNode(val);
        NewNode->next=dummyhead->next;
        dummyhead->next=NewNode;
        size++;
    }
    
    void addAtTail(int val) {
        LinkedNode*NewNode=new LinkedNode(val);
        LinkedNode*cur=dummyhead;
        while(cur->next!=nullptr)
        {
            cur=cur->next;
        }
        cur->next=NewNode;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        LinkedNode*NewNode=new LinkedNode(val);
        LinkedNode*cur=dummyhead;
        if(index>size)
            return;
        if(index==0)
            addAtHead(val);
        else if(index==size)
            addAtTail(val);
        else
        {
            while(index)
        {
            cur=cur->next;
            index--;
        }
        NewNode->next=cur->next;
        cur->next=NewNode;
        size++;
        }
    }
    
    void deleteAtIndex(int index) {
        if(index<0||index>=size)
            return;
        LinkedNode*cur=dummyhead;
        while(index)
        {
            cur=cur->next;
            index--;
        }
        LinkedNode*tmp=cur->next;
        cur->next=cur->next->next;
        delete tmp;
        tmp=nullptr;
        size--;
    }
private:
    int size;
    LinkedNode* dummyhead;
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

你可能感兴趣的:(矩阵,链表,线性代数)