[leetcode]20150704b
1、N-Queens
题目
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens’ placement, where ‘Q’ and ‘.’ both indicate a queen and an empty space respectively.
For example,
There exist two distinct solutions to the 4-queens puzzle:
[
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],
["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
思路
考察递归。
参考linhuanmars。这个博客总结的挺好的,特别是相似类型题目的整理。推荐刷题的看看。
代码
public class Solution {
public List<List<String> > solveNQueens(int n) {
ArrayList<ArrayList<String> > res = new ArrayList<ArrayList<String> >();
helper(n,0,new int[n], res);
return (List)res;
}
private void helper(int n, int row, int[] columnForRow, ArrayList<ArrayList<String> > res)
{
if(row == n) //到达最后一行
{
ArrayList<String> item = new ArrayList<String>();
for(int i=0;i<n;i++)
{
StringBuilder strRow = new StringBuilder();
for(int j=0;j<n;j++)
{
if(columnForRow[i]==j)
strRow.append('Q');
else
strRow.append('.');
}
item.add(strRow.toString());
}
res.add(item);
return;
}
for(int i=0;i<n;i++)
{
columnForRow[row] = i;
if(check(row,columnForRow))
{
helper(n,row+1,columnForRow,res);
}
}
}
private boolean check(int row, int[] columnForRow)
{
for(int i=0;i<row;i++)
{
if(columnForRow[row]==columnForRow[i] || Math.abs(columnForRow[row]-columnForRow[i])==row-i)
return false;
}
return true;
}
}
总结
大一用的那本书叫什么来着?《程序设计引导及在线实践》。里面貌似总结了一些类似枚举、递归、回溯之类的东西,貌似和贪心、动归的算法设计思想在概念上不一样,叫做程序设计思想吧?怎么样。
2、Number of Islands
题目
Given a 2d grid map of ‘1’s (land) and ‘0’s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
11110
11010
11000
00000
Answer: 1
Example 2:
11000
11000
00100
00011
Answer: 3
Credits:
Special thanks to @mithmatt for adding this problem and creating all test cases.
思路
类似深度优先搜索?
代码
public class Solution {
public int numIslands(boolean[][] grid) {
int m = grid.length;
if(m==0) return 0;
int n = grid[0].length;
if(n==0) return 0;
int ans = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid[i][j]!=true) continue;
ans ++;
dfs(grid,i,j,m,n);
}
}
return ans;
}
private void dfs(boolean[][] grid, int i ,int j, int m,int n){
if(i<0 || i >=m || j<0 || j>=n) return;
if(grid[i][j] == true){
grid[i][j] = false;
dfs(grid,i-1,j,m,n);
dfs(grid,i+1,j,m,n);
dfs(grid,i,j-1,m,n);
dfs(grid,i,j+1,m,n);
}
}
}
总结
3、Permutations II
题目
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2] have the following unique permutations:
[1,1,2], [1,2,1], and [2,1,1].
思路
参考linhuanmars and programcreek
每次准备swap前,检查一下[start,i]是否有重复元素,有则说明该元素已交换到start位置处过,所以不再交换。
代码
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
int length = nums.length;
List<List<Integer> > ans = (List)new ArrayList<ArrayList<Integer> >();
if(length==0) return ans;
Arrays.sort(nums);
perm(nums,0,length-1,ans);
return ans;
}
private void perm(int[] nums,int start,int end,List<List<Integer> > ans)
{
if(start == end){
List<Integer> item = (List)new ArrayList<Integer>();
for(int i = 0; i <= end; i++)
item.add(nums[i]);
ans.add(item);
return;
}
for(int i = start; i <= end; i++){
if(i == start) perm(nums,start+1,end,ans);
else if(containsDuplicate(nums,start,i)){
swap(nums,start,i);
perm(nums,start+1,end,ans);
swap(nums,start,i); //回溯
}
}
}
private void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
private boolean containsDuplicate(int[] nums, int start, int end) {
for (int i = start; i <= end-1; i++) {
if (arr[i] == arr[end]) {
return false;
}
}
return true;
}
}
//预先排序,从排序数组里挑选出候选元素的方法
public class Solution{
public List<List<Integer>> permuteUnique(int[] num) {
List<List<Integer>> res = (List)new ArrayList<ArrayList<Integer>>();
if(num==null && num.length==0)
return res;
Arrays.sort(num);
helper(num, new boolean[num.length], new ArrayList<Integer>(), res);
return res;
}
private void helper(int[] num, boolean[] used, ArrayList<Integer> item, List<List<Integer>> res)
{
if(item.size() == num.length)
{
res.add(new ArrayList<Integer>(item));
return;
}
for(int i=0;i<num.length;i++)
{
if(i>0 && !used[i-1] && num[i]==num[i-1]) continue;
if(!used[i])
{
used[i] = true;
item.add(num[i]);
helper(num, used, item, res);
item.remove(item.size()-1);
used[i] = false;
}
}
}
}
总结
- 第一次通过Arrays.sort(nums)排序,nums[i] != nums[i-1]比较来检查重复,但是出错,为什么?
因为swap后顺序乱了。 - 第二次通过containsDuplicate显式检查通过了。
- Java集合类List\Set等,类型转换。
4、Permutations
题目
Given a collection of numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].
思路
递归。
和《数据结构基础》里面的习题类似,每次把当前考虑的数和后续的每一个数swap,递归求后续部分的全排列。
代码
public class Solution {
public List<List<Integer>> permute(int[] nums) {
int length = nums.length;
List<List<Integer> > ans = (List)new ArrayList<ArrayList<Integer> >();
if(length==0) return ans;
perm(nums,0,length-1,ans);
return ans;
}
private void perm(int[] nums,int start,int end,List<List<Integer> > ans)
{
if(start == end){
List<Integer> item = (List)new ArrayList<Integer>();
for(int i = 0; i <= end; i++)
item.add(nums[i]);
ans.add(item);
return;
}
for(int i = start; i <= end; i++){
if(i == start) perm(nums,start+1,end,ans);
else if(nums[i] != nums[start]){
swap(nums,start,i);
perm(nums,start+1,end,ans);
swap(nums,start,i); //回溯
}
}
}
private void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
总结
和上一题的区别在哪里?
5、Binary Tree Right Side View
题目
Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
For example:
Given the following binary tree,
1 <—
/ \
2 3 <—
\ \
5 4 <—
You should return [1, 3, 4].
Credits:
Special thanks to @amrsaqr for adding this problem and creating all test cases.
思路
按照前序遍历二叉树,每次把结点的值加入到结果中时,加入到一个HashMap中,以深度为健。
所以相同深度,左子树先加入的值会被右子树覆盖,而如果右子树没有结点则左子树结点会被保留下来。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> rightSideView(TreeNode root) {
HashMap<Integer, Integer> depthToValue = new HashMap<Integer, Integer>();
dfs(depthToValue, root, 1);
int depth = 1;
List<Integer> result = new ArrayList<Integer>();
while (depthToValue.containsKey(depth)) {
result.add(depthToValue.get(depth));
depth++;
}
return result;
}
private void dfs(HashMap<Integer, Integer> depthToValue, TreeNode node, int depth) {
if (node == null) {
return;
}
depthToValue.put(depth, node.val);
dfs(depthToValue, node.left, depth + 1);
dfs(depthToValue, node.right, depth + 1);
}
}
总结
jiuzhang.com九章算法上面有答案。