前言

本文隶属于专栏《LeetCode 刷题汇总》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构请见LeetCode 刷题汇总

正文

幕布

在这里插入图片描述

幕布链接

51. N 皇后

题解

回溯算法(转换成全排列问题 + 剪枝)- 题解后有相关问题

3个set,i,row+i,row-i

import scala.collection.mutable.{ListBuffer, Set}

object Solution {
  val col, diagonal1, diagonal2 = Set[Int]()
  var N : Int = _

  def solveNQueens(n: Int): List[List[String]] = {
    N = n
    val res = ListBuffer[List[String]]()
    rec(res, ListBuffer(), 0)
    res.toList
  }

  def rec(res: ListBuffer[List[String]], list: ListBuffer[String], row: Int): Unit = {
    if (row == N) {
      res += list.toList
      return
    }
    for (i <- 0 until N if !col.contains(i) && !diagonal1.contains(row + i) && !diagonal2.contains(row - i)) {
      val chars = Array.fill(N)('.')
      chars(i) = 'Q'
      list += new String(chars)
      col += i
      diagonal1 += row + i
      diagonal2 += row - i
      rec(res, list, row + 1)
      list.remove(list.size - 1)
      col -= i
      diagonal1 -= row + i
      diagonal2 -= row - i
    }
  }
}

52. N皇后 II

题解

官方题解

DFS + 位运算剪枝

class Solution {
    private int ans = 0;

    public int totalNQueens(int n) {
        dfs(n, 0, 0, 0, 0);
        return ans;
    }

    private void dfs(int n, int row, int col, int ld, int rd) {
        if (row >= n) { 
            ans++; 
            return; 
        }
        int bits = ~(col | ld | rd) & ((1 << n) - 1);   // 1
        while (bits > 0) {   // 2
            int pick = bits & -bits; // 3
            dfs(n, row + 1, col | pick, (ld | pick) << 1, (rd | pick) >> 1); //4
            bits &= bits - 1; // 5
        }
    }
}

解释说明

(1 << n) - 1

生成了n个1.这里的1表示可以放置皇后
其实就是初始化了n个1,在不考虑皇后之间可以相互攻击的情况下,n个位置都可以放皇后

~(col | ld | rd)

三个变量分别代表了列以及两个斜线的放置情况。
这里的1表示的是不能放置皇后(就是相应的列或斜线上已经放置过皇后了)
因此 int bits = ~(col | ld | rd) & ((1 << n) - 1); 表示的是考虑了相应列、斜线后能放置皇后的位置。

举例

n=4时,初始化为1111,表示此时4个位置都可以放皇后
但是和~~(col | ld | rd)按位与后变为了0110
表示此时只有第2个和第3个位置是可以放皇后的。

bits > 0

当bits>0时,说明bits中还有1存在,就说明遍历还没有完成。
而在之后的循环体中,每遍历bits中的一个1,就会将其清0,这就是代码中注释部分 5 的语句。

pick

这里的 pick 就是取出了最后一位1,表示此时遍历的是这种情况。
假设 bits 为0110,取出最后一位1后,就变为0010,就是将皇后放在第3个位置。

row+1

不难理解,就是因为之前已经在row行放置了皇后了,现在应该搜索下一行可能的位置了。

col | pick

就是把目前所有放置皇后的列都计算出来了,比如最开始计算时col是0000,pick是0010,那么col | pick就是0010,意思就是第三列被放置过了。

(ld | pick) << 1

假设ld是0000,ld | pick就是0010,左移1位后变成了0100,意思就是下一行的第二列也不要放皇后了,因为在这一行的第三列我已经放过了,他们是位于一个斜线上的。

(rd | pick) >> 1

跟(ld | pick) << 1是一个含义

位运算

x & -x

这个操作可以保留最后一位1,而其他位都会清零

补码

正数 => 本身
负数 => 反码 + 1

举例
00110110 -> 00000010
变成负数->
10110110
反码->
11001001
补码->
11001010
按位与 00110110->
00000010

x & (x - 1)

    最低位
        1
            最低位如果是1,减1后就变为了0,按位与后,其他位不发生变化,最低位清为0.
        0
            如果最低位是0,那么减1后,这个0就变为了1,并且向高位借位,直到遇到第一个1,这个1会因为之前的借位变成0,此时借位清0,更高位的数据就不会发生变化。这样按位与后,最低位的1就变成了0,而其他的数并没有变化。

53. 最大子序和

题解

官方题解

max,cur

object Solution {
  def maxSubArray(nums: Array[Int]): Int = {
    var max, cur = nums(0)
    for (i <- 1 until nums.length) {
      cur = math.max(nums(i), cur + nums(i))
      max = math.max(max, cur)
    }
    max
  }
}

54. 螺旋矩阵

题解

Super Simple and Easy to Understand Solution

rowMin, rowMax, colMin, colMax,→ ↓ ← ↑

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> list = new ArrayList<>();
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0) return list;
        
        int rowMin = 0, rowMax = matrix.length-1, colMin = 0, colMax = matrix[0].length-1;
        while(rowMin <= rowMax && colMin <= colMax) {
            for(int i=colMin; i<=colMax; i++) list.add(matrix[rowMin][i]);
            rowMin++;
            
            for(int i=rowMin; i<=rowMax; i++) list.add(matrix[i][colMax]);
            colMax--;
            
            if(rowMin > rowMax || colMin > colMax) break;
            
            for(int i=colMax; i>=colMin; i--) list.add(matrix[rowMax][i]);
            rowMax--;
            
            for(int i=rowMax; i>=rowMin; i--) list.add(matrix[i][colMin]);
            colMin++;
        }
        return list;
    }
}

55. 跳跃游戏

题解

Java Solution easy to understand

if (curMax < i) return false; curMax 代表经过每一个点能到达的最远距离

class Solution {
    public boolean canJump(int[] nums) {
        int curMax = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (curMax < i) return false;
            curMax = Math.max(curMax, i + nums[i]);
        }
        return true;  
    }
}
上一篇 下一篇