首页 > 代码库 > (每日算法)LeetCode--Set Matrix Zeroes (矩阵置零)

(每日算法)LeetCode--Set Matrix Zeroes (矩阵置零)

给定一个矩阵,如果有零元素那么就将零元素所在的行和列都置为零。

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.

最直观的解法就是开辟一个新的矩阵,当原矩阵存在零元素的时候,就将新矩阵的对应行和列置为零。这样空间复杂度较高,也是题目不允许的。

题目的难点就在于,如果遇到零元素之后马上在矩阵上操作,将所在的行和列都置为零。在接下来的遍历中,如果你再遇到零,你讲不清楚是原矩阵的零还是你修改之后的零。所以,一种方法就是先通过两个数组来记录该行该列上有没有零元素,等对矩阵遍历完之后再统一修改即可

class Solution {
public:
    void setZeroes(vector<vector<int> > &matrix) {
  
	    const size_t m = matrix.size();
	    const size_t n = matrix[0].size();
	    vector<bool> row(m, false); //标记该行是否存在0
	    vector<bool> col(n, false);
	    
	    for(int i = 0; i < matrix.size(); i++)
	    {
	    	for(int j = 0; j < matrix[0].size(); j++)
		{
			if(matrix[i][j] == 0)
				row[i] = col[j] = true;//如果原矩阵中存在0,记录该行和列的位置。
		}
	    }

	 for (size_t i = 0; i < m; ++i) {
		if (row[i])
			fill(&matrix[i][0], &matrix[i][0] + n, 0);//将矩阵的一行置为零
		}
	for (size_t j = 0; j < n; ++j) {
		if (col[j]) {
			for (size_t i = 0; i < m; ++i) 
				matrix[i][j] = 0;//将矩阵的一列置为0
		       	}
	}
    }
};

fill函数的作用是:将一个区间的元素都赋予val值。函数参数:fill(first,last,val);//first为容器的首迭代器,last为容器的末迭代器,val为将要替换的值。

作用和下面的函数相同:

template <class ForwardIterator, class T>
  void fill (ForwardIterator first, ForwardIterator last, const T& val)
{
  while (first != last) {
    *first = val;
    ++first;
  }
}
使用fill函数的一个例子:

// fill algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::fill
#include <vector>       // std::vector

int main () {
  std::vector<int> myvector (8);                       // myvector: 0 0 0 0 0 0 0 0

  std::fill (myvector.begin(),myvector.begin()+4,5);   // myvector: 5 5 5 5 0 0 0 0
  std::fill (myvector.begin()+3,myvector.end()-2,8);   // myvector: 5 5 5 8 8 8 0 0

  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

输出是:myvector contains: 5 5 5 8 8 8 0 0

fill_n函数的作用是:给你一个起始点,然后再给你一个数值count和val。把从起始点开始依次赋予count个元素val的值

相当于下面的函数:

template <class OutputIterator, class Size, class T>
  OutputIterator fill_n (OutputIterator first, Size n, const T& val)
{
  while (n>0) {
    *first = val;
    ++first; --n;
  }
  return first;     // since C++11
}

在C++11中返回首迭代器的值,在c++98中什么都不返回。n在98中不能为负数,在11中,如果为负数,则什么也不做。

一个例子:

// fill_n example
#include <iostream>     // std::cout
#include <algorithm>    // std::fill_n
#include <vector>       // std::vector

int main () {
  std::vector<int> myvector (8,10);        // myvector: 10 10 10 10 10 10 10 10

  std::fill_n (myvector.begin(),4,20);     // myvector: 20 20 20 20 10 10 10 10
  std::fill_n (myvector.begin()+3,3,33);   // myvector: 20 20 20 33 33 33 10 10

  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
这也就引出来指针和迭代器的区别:

相同点---指针和iterator都支持与整数进行+-运算,而且其含义都是从当前位置向前或者向后移动n个位置;指针和iterator都支持减法运算,指针-指针得到的是两个指针之间的距离,迭代器-迭代器得到的是两个迭代器之间的距离 通过指针或者iterator都能够修改其指向的元素。

不同点--- cout操作符可以直接输出指针的值,但是对迭代器进行在操作的时候会报错。通过看报错信息和头文件知道,迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用*取值后的值而不能直接输出其自身;  指针能指向函数而迭代器不行,迭代器只能指向容器。


指针是一种特殊的变量,它专门用来存放另一变量的地址,而迭代器只是参考了指针的特性进行设计的一种STL接口。

网上有这样一种说法:迭代器是广义指针,而指针满足所有迭代器要求。迭代器是STL算法的接口,而指针是迭代器,因此STL算法可以使用指针来对基于指针的非STL容器进行操作。

也许某些编译器使用指针来实现迭代器以至于有些人会误以为指针和迭代器是一个概念来的。

迭代器并不是普通的指针,可以说是智能指针。只有在vector容器中Iterator才是普通的指针。其他情况Iterator都是比较复杂的数据就够。Iterator分为了只读、只写、向前、双向和随机访问五种不同的类型。根据容器的不同和使用的情况,Iterator使用不同的类型。像List就是双向的Iterator。所有的Iterator都符合左闭右开的原则。





(每日算法)LeetCode--Set Matrix Zeroes (矩阵置零)