螺旋矩阵和链表的知识

59螺旋矩阵Ⅱ

54螺旋矩阵

剑指Offer 29.顺时针打印矩阵

54题和29题其实是一模一样的题

螺旋矩阵这种题考的不是什么算法,就是一种

思路,一种模拟过程,对代码的掌控能力。

 从上图可以看出来坚持左闭右开的政策,就是每次拐角处留给新的一边来画,一直坚持用左闭右开的政策,这样代码不会乱,不要一会左开右闭,一会左闭右闭的,这些容易把自己思路搞乱。

就顺时针画矩阵:

1.上行从左到右

2.右列从上到下

3.下行从右到左

4.左列从下到上

下面就是59题代码

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>>res(n,vector<int>(n,0));
        int startx = 0,starty = 0; //循环的起始位置
        int loop = n/2; //循环的圈数
        int mid = n/2;  //判断矩阵是否有中间位置,奇数矩阵是有的
        int count = 1; //需要填充的数字
        int offset = 1;
        int i,j;
        while(loop--)
        {
            i = startx;
            j = starty;

            //填充上行从左到右
            for(;j<starty + n - offset;j++)
            {
                res[i][j] = count++;
            }

            //填充右列从上到下
            for(;i<startx + n -offset;i++)
            {
                res[i][j] = count++;
            }

            //填充下行从右到左
            for(;j>starty;j--)
            {
                res[i][j] = count++;
            }

            //填充左列从下到上
            for(;i>startx;i--)
            {
                res[i][j] = count++;
            }

            //第二圈的起始位置 
            startx++;
            starty++;

            offset += 2;
        }
        if(n%2)  //如果这个矩阵是奇数矩阵是有中心位置的
        {
            res[mid][mid] = count;
        }
        return res;
    }
};

对于54题我刚开始也想用59题这样的思想,但是我发现出现了各种各样的小bug,因为54题他没有说行列相等所以要考虑一些问题,比如就一行的时候我们要考虑,就不能把拐角处留个另外一边了等等之类的因素吧,所以就换了一种思路,就是我先每次读取一行然后再判断读取完这一行,剩下来的首行是否大于低,如果大于证明读取完毕,如果没有继续,读右边这一列的所有元素,读取判断是否小于左边这列,如果没有继续,如果小于就跳出while,然后再读取底那一行,判断是否小于重新定义的首行如果小于就跳出,不小就继续读取左边一列,这样一次反复直到跳出循环为止。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector <int> ans;
        if(matrix.empty()) return ans; //若数组为空,直接返回答案
        int u = 0; //赋值上下左右边界
        int d = matrix.size() - 1;
        int l = 0;
        int r = matrix[0].size() - 1;
        while(true)
        {
            for(int i = l; i <= r; i++) ans.push_back(matrix[u][i]); //向右移动直到最右
            if(++ u > d) break; //重新设定上边界,若上边界大于下边界,则遍历遍历完成,下同
            for(int i = u; i <= d; i++) ans.push_back(matrix[i][r]); //向下
            if(-- r < l) break; //重新设定有边界
            for(int i = r; i >= l; i--) ans.push_back(matrix[d][i]); //向左
            if(-- d < u) break; //重新设定下边界
            for(int i = d; i >= u; i--) ans.push_back(matrix[i][l]); //向上
            if(++ l > r) break; //重新设定左边界
        }
        return ans;
    }
};

29与54题是一样的题,这里就不再详细描述了。

链表的知识

 我们平时在刷leetcode题的时候,链表节点都定义好了,直接用就行,这样我们会漏掉一个知识点就是链表节点的定义

struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

如果我们写第四行节点的构造函数也可以,因为C++默认生成一个构造函数,但是不能初始化成员变量,自己定义节点构造函数:

ListNode* head = new ListNode(5);

使用默认构造函数初始化节点:

ListNode* head = new ListNode();
head->val = 5;

经典对比 

 数组在定义的时候,长度是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。

链表长度可以不是固定的,并且可以动态增删,适合数量不固定,频繁增删,减少查询的场景。

 203移除链表元素

707设计链表

对于203这题属于简单题,最终想学习的一个思想就是添加一个虚拟的头节点,这个思想来源于链表上加一个头节点(不存数,只存链表长度,和指向第一个节点的指针)这样会让整个链表的增删操作一体化,如果不增加虚拟头节点这题的代码为(代码中那段注释应该注意):

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        // 删除头结点
        while (head != NULL && head->val == val) { // 注意这里不是if
            ListNode* tmp = head;
            head = head->next;
            delete tmp;
        }

        // 删除非头结点
        ListNode* cur = head;
//应该先判断p是否为空而不能先判断p->next是否为空,如果先判断后者会出现直接给你一个空链表,这样就会报错!
        while (cur != NULL && cur->next!= NULL) {
            if (cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } else {
                cur = cur->next;
            }
        }
        return head;
    }
};

上面这段代码分了一下头节点和非头节点,下面是带虚拟节点的:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
        dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
        ListNode* cur = dummyHead;
        while (cur->next != NULL) {
            if(cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } else {
                cur = cur->next;
            }
        }
        head = dummyHead->next;
        delete dummyHead;
        return head;
    }
};

显然操作方便很多,而且记得最后把你设置的虚拟头节点删除。

对于707题,个人觉得就是考察你对链表的一系列操作吧,考察你头插,尾插,删除,这些各种操作吧,这个你初始化一个虚拟头节点很方便,再定义一个你的链表长度,这样在你按位置查找节点内元素val值为多少更好判断一些。在类中你需要用到一些什么属性的时候需要定义一下私有属性,然后再去操作。

class MyLinkedList {
public:
    struct ListNode{
        int val;
        ListNode *next;
        ListNode(int x):val(x),next(NULL){}
    };
    MyLinkedList() {
      dummyHead = new ListNode(0);
      size = 0;  
    }
    
    int get(int index) {
        if(index > (size-1) || index < 0)
        {
            return -1;
        }
        ListNode *p = dummyHead->next;
        while(index--) //如果--index就会陷入死循环 如果index为0的时候 --index=-1,C++规定while语句任意非0值都为真,所以会陷入死循环。
        {
            p = p->next;
        }
        return p->val;
    }
    
    void addAtHead(int val) {
        ListNode *addHead = new ListNode(val);
        addHead->next = dummyHead->next;
        dummyHead->next = addHead;
        size++;
    }
    
    void addAtTail(int val) {
        ListNode *addTail = new ListNode(val);
        ListNode *p = dummyHead;
        int index = size;
        while(index--) //这个判断条件也可以写完cur->next != NULL
        {
            p = p->next;
        }
        p->next = addTail;
        addTail->next = NULL;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        ListNode *p = dummyHead;
        ListNode *addIndex = new ListNode(val);
        // if(index < 0)
        // {
        //     addAtHead(val);
        // }
        // if(index == size)
        // {
        //     addAtTail(val);
        // }
        if(index > size)
        {
            return;
        }
        while(index--)
        {
            p = p->next;
        }
        addIndex->next = p->next;
        p->next = addIndex;
        size++;
    }
    
    void deleteAtIndex(int index) {
        ListNode *p = dummyHead;
        if(index <0 || index >=size)
        {
            return;
        }
        while(index--)
        {
            p = p->next;
        }
        ListNode *tmp;
        tmp = p->next;
        p->next = tmp->next;
        delete tmp;
        size--;
    }
private:
    ListNode *dummyHead;
    int size;
};

/**
 * 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);
 */

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值