算法第三天

螺旋矩阵

力扣链接:[59.螺旋矩阵](Loading Question... - 力扣(LeetCode))

【题目描述】

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

【示例】

示例1:

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

示例2:

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

【思路】

本题的话没有涉及到其他算法,就是比较考虑解题者对代码运算的掌控能力。

我在刚拿上手的时候,对这个螺旋矩阵进行了各种花里胡哨的旋转填充,但都会由于奇奇怪怪的边界条件被终止。然后看到卡尔大神对于本题的分析——坚持循环不变量,我发现了我对于边界条件的处理并不统一,这也就导致了循环始终无法正常运算下去。根据题目的设定,整个矩阵的模拟绘制过程应该是这样的:

  • 上行从左到右填充
  • 右列从上到下填充
  • 下行从右到左填充
  • 左列从下到上填充

重复上面的填充过程直至画完。

在上面我们提到了循环不变量,因此我们在编写代码前就应该对每条边的处理做好一个限定,在此我选择的是左闭右开的原则,对于代码具体的实现逻辑在下面稍加分析。

【代码】

本题依然是选择了C#

public class Solution {
    public int[][] GenerateMatrix(int n) {
        int[][] result = new int[n][];
        for(int index = 0;index<n;index++)
            result[index] = new int[n];
        int x = 0, y = 0;       //用于定义每个循环圈的起始位置
        int loop = n / 2;		
        int offset = 1;
        int count = 1;
        int i, j;       //分别表示x,y坐标
        while(loop-- > 0) 
        {
            i = x;
            j = y;
            for (j = x; j < n - offset; j++)result[i][j] = count++;
            for(i = y; i < n-offset;i++)result[i][j] = count++;
            for(; j > y; j--)result[i][j] = count++;
            for (; i > x; i--)result[i][j] = count++;
            offset++;
            x++;
            y++;
        }
        if(n%2==1)
        {
            result[n/2][n/2] = count;
        }
        return result;
    }
}

在分析前不得不吐槽一下c#中的交错数组多维数组,在本题中不能像其他语言一样使用二维数组来解决问题,需要建立一个二维交错数组,并对该数组进行初始化。

可以看到先设定了每次圈循环的开始位置坐标,然后通过对题目的分析,循环圈数等于输入N的一半,而offset的作用就是每次圈循环遍历完就缩短边界,count用来给当前数组元素赋值。

我们还要注意对n为奇数的情况进行特殊处理,即最后的if赋值。


移出链表元素

力扣链接:[203.移除链表元素](203. 移除链表元素 - 力扣(LeetCode))

【题目描述】

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

【示例】

示例1:

输入: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
输出:[]

【思路】

因为在以前学习过数据结构,还有一定的链表基础,因此对于本题我有两种想法来解决。

原链表删除

首先我先对head头结点进行操作,如果head != null && head.val == val就让head等于它的next,注意此时我们需要使用while,需要考虑到删除链表的元素可能会是一个持续移除的过程,当删除的目标数值和链表中所有元素都相同时往往就会出现这个问题。

然后对头结点处理完之后,再定义一个新的指针指向头结点,并对他进行判断,如果它的下一个结点的数值等于目标值,则cur.next = cur.next.next,否则就让当前结点继续遍历指向下一个节点cur = cur.next直到为空。

虚拟结点删除

首先初始化一个新结点,让他的next结点指向head,从而形成一条链,然后的操作与上面基本类似,但在最后的返回时要注意返回的是新结点的next。

【代码】

原链表删除

public class Solution {
    public ListNode RemoveElements(ListNode head, int val) {
        while(head != null && head.val == val)
        {
            head = head.next;
        }
        if(head == null)
        return head;

        ListNode cur = head;
        while( cur != null && cur.next != null)
        {
            if(cur.next.val == val)
            {
                cur.next = cur.next.next;
            }
            else
            {
                cur = cur.next;
            }
        }
        return head;
    }
}

虚拟结点删除

public class Solution {
    public ListNode RemoveElements(ListNode head, int val) {
        ListNode node = new ListNode(0,head);
        ListNode temp = node;
        while(temp.next != null)
        {
            if(temp.next.val == val)
            {
                temp.next = temp.next.next;
            }
            else
            {
                temp = temp.next;
            }
        }
        return node.next;
    }
}
posted @ 2023-06-15 17:50  asjdqi  阅读(12)  评论(0)    收藏  举报