目录
前言
总结回溯算法的题型
按照规模将其题型都熟练掌握
学习的链接大框架为:
回溯算法理论基础
LinkedList<Integer> sonlist=new LinkedList<>();
双向链表可以删除最前或者添加最前的节点,删除的时候通过removeLast();List<Integer> sonlist=new ArrayList<>();
单链表只能添加,或者删除,删除的时候通过remove(下标值)
组合
77. 组合(中等)
题目:
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:
输入:n = 1, k = 1
输出:[[1]]
提示:
1 <= n <= 20
1 <= k <= n
思路:
class Solution {
List<List<Integer>> list =new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist=new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
if (k <= 0 || n < k) {
return list;
}
backtrace(n,k,1);
return list;
}
public void backtrace(int n,int k,int startindex){
if(sonlist.size()==k){
list.add(new ArrayList<>(sonlist));
return;
}
for(int i=startindex;i<=n;i++){
sonlist.addLast(i);
backtrace(n,k,i+1);
//不用带下标
sonlist.removeLast();
}
}
}
也可以将以上的双向列表换为如下:Deque<Integer> sonlist=new ArrayDeque<>();
进一步的优化,将其for条件的循环更改为:
for(int i=startindex;i<=n-(k-sonlist.size())+1;i++){
这是因为如果 n = 7, k = 4,从 5 开始搜索就已经没有意义了
优化过程:
已经选择的元素个数:sonlist.size();
还需要的元素个数为: k - sonlist.size();
在集合n中至多要从该起始位置 : n - (k - sonlist.size()) + 1,开始遍历
为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。
代码如下:
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
if(k <= 0 || n < k){
return list;
}
backtrace(n,k,1);
return list;
}
public void backtrace(int n,int k,int startindex){
if(sonlist.size() == k){
list.add(new ArrayList<>(sonlist));
return ;
}
for(int i = startindex;i <= (n - (k - sonlist.size())) + 1;i++){
sonlist.addLast(i);
backtrace(n,k,i+1);
// 移除最后一个元素不用带下标
sonlist.removeLast();
}
}
}
如果内部使用LinkedList函数则需要注意的点在删除最后一个元素的值
class Solution {
//列表的形式
List<List<Integer>> list =new ArrayList<List<Integer>>();
//双向列表的形式
List<Integer> sonlist=new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
backtrace(n,k,1);
return list;
}
public void backtrace(int n,int k,int startindex){
if(sonlist.size()==k){
//双向列表强转换为列表
list.add(new ArrayList(sonlist));
return;
}
for(int i=startindex;i<=n;i++){
sonlist.add(i);
backtrace(n,k,i+1);
sonlist.remove(sonlist.size()-1);
}
}
}
216. 组合总和 III(中等)
题目:
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
只使用数字1到9
每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。
示例 3:
输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。
提示:
2 <= k <= 9
1 <= n <= 60
思路:
计算其sum值,可以将其sum值也遍历,不用额外定义一个int sum在函数外。
注意其终止条件
class Solution {
List<List<Integer>> list=new ArrayList<>();
LinkedList<Integer> sonlist =new LinkedList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
backtrace(k,n,1,0);
return list;
}
public void backtrace(int k,int n,int startindex,int sum){
if(sum>n)return;
if(sonlist.size()==k){
if(sum==n)list.add(new ArrayList<>(sonlist));
return;
}
for(int i=startindex;i<=9-(k-sonlist.size())+1;i++){
sonlist.addLast(i);
sum=sum+i;
backtrace(k,n,i+1,sum);
sonlist.removeLast();
sum=sum-i;
}
}
}
39. 组合总和(中等)
题目:
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例 1:
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
示例 2:
输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:
输入: candidates = [2], target = 1
输出: []
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都 互不相同
1 <= target <= 500
思路:
这题的思路主要跟上面的区别,在于数组是可以重复使用。
class Solution {
List<List<Integer>> list=new ArrayList<List<Integer>>();
//删除回溯使用双端队列比较好
LinkedList<Integer> sonlist=new LinkedList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates); // 先进行排序
backtrace(candidates,target,0,0);
return list;
}
public void backtrace(int []candidates,int target,int sum,int startindex){
//如果sum大于target 优先返回
if(sum>target)return ;
//记得转换类型
if(sum==target){
list.add(new ArrayList<>(sonlist));
return;
}
//从startindex开始遍历,而且条件是小于数组长
for(int i=startindex;i<candidates.length;i++){
sonlist.addLast(candidates[i]);
sum=sum+candidates[i];
//这里的数组值是可以重复的,所以startindex是可以为i本身自已。
backtrace(candidates,target,sum,i);
//移除最新的节点,也要移除sum中那个数组值
sonlist.removeLast();
sum=sum-candidates[i];
}
}
}
40. 组合总和 II(中等)
题目:
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
提示:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
思路:
这道题跟上面的思路是大同小异,差不多,区别在于不可重复使用,但是数组中有值一样,遍历出来的列表,可能会有重复的,类似这种.
解决上面的问题:把所有组合求出来,再用set或者map去重,这么做很容易超时!
所以要在搜索的过程中就去掉重复组合。
可以通过外加这一行代码,具体如下所示:
只要大于下标值,而且值和之前那个相等,既跳过该下标即可
if(i>startindex&&candidates[i]==candidates[i-1])continue;
完整代码如下所示:
class Solution {
List<List<Integer>> list =new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist=new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
backtrace(candidates,target,0,0);
return list;
}
public void backtrace(int []candidates,int target,int sum,int startindex){
if(sum>target)return;
if(sum==target){
list.add(new ArrayList<>(sonlist));
return ;
}
for(int i=startindex;i<candidates.length;i++){
if(i>startindex&&candidates[i]==candidates[i-1])continue;
sonlist.addLast(candidates[i]);
sum=sum+candidates[i];
backtrace(candidates,target,sum,i+1);
sonlist.removeLast();
sum=sum-candidates[i];
}
}
}
也可以通过一维的标记数组,标记其已经使用过该数字了
class Solution {
List<List<Integer>> list =new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist=new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
//定义一个一维标记数组
boolean [] flag=new boolean [candidates.length];
backtrace(candidates,target,0,0,flag);
return list;
}
public void backtrace(int []candidates,int target,int sum,int startindex,boolean [] flag){
if(sum>target)return;
if(sum==target){
list.add(new ArrayList<>(sonlist));
return ;
}
for(int i=startindex;i<candidates.length;i++){
//比较的是前一个数组,数组的boolean也是上一个值
if(i>0&&candidates[i]==candidates[i-1]&&flag[i-1]==false)continue;
sonlist.addLast(candidates[i]);
sum=sum+candidates[i];
//一开始初始化为true
flag[i]=true;
backtrace(candidates,target,sum,i+1,flag);
//回溯之后变为false,标记数组
flag[i]=false;
sonlist.removeLast();
sum=sum-candidates[i];
}
}
}
可配合如下进行理解:
(关于该图来源于 代码随想录的网址)
子集
78. 子集(中等)
题目:
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
nums 中的所有元素 互不相同
思路:
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
// 此处使用ArrayList 以及 LinkedList 用法不同
LinkedList<Integer> sonlist = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
backtrace(nums,0);
return list;
}
public void backtrace(int[] nums,int index){
//「遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合」。
list.add(new ArrayList<>(sonlist));
//终止条件本身可不加
if(sonlist.size() > nums.length)return ;
for(int i = index;i < nums.length;i++){
sonlist.addLast(nums[i]);
backtrace(nums,i + 1);
sonlist.removeLast();
}
}
}
或者使用ArryaList
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
// 此处使用ArrayList 以及 LinkedList 用法不同
List<Integer> sonlist = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
backtrace(nums,0);
return list;
}
public void backtrace(int[] nums,int index){
//「遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合」。
list.add(new ArrayList<>(sonlist));
//终止条件本身可不加
if(sonlist.size() > nums.length)return ;
for(int i = index;i < nums.length;i++){
sonlist.add(nums[i]);
backtrace(nums,i + 1);
sonlist.remove(sonlist.size() - 1);
}
}
}
90. 子集 II(中等)
题目:
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例 1:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
思路:
添加标记数组:
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist = new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
//先排好顺序,因为数组内的数值可能重复,子集不能重复
Arrays.sort(nums);
boolean[] flag = new boolean[nums.length];
backtrace(nums,0,flag);
return list;
}
public void backtrace(int[] nums,int startindex,boolean[] flag){
//该算法为找子集,每一次遍历都可以输出添加
list.add(new ArrayList<>(sonlist));
if(sonlist.size() > nums.length)return;
for(int i = startindex;i < nums.length;i++){
// 核心代码在这一块细节
//通过大于下标以及如果两者相等,跳过该循环
if(i > 0 && nums[i] == nums[i - 1] && flag[i - 1] == false)continue;
sonlist.addLast(nums[i]);
flag[i]=true;
backtrace(nums,i + 1,flag);
flag[i]=false;
sonlist.removeLast();
}
}
}
不添加标记数组的方式:
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist = new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
//先排好顺序,因为数组内的数值可能重复,子集不能重复
Arrays.sort(nums);
backtrace(nums,0);
return list;
}
public void backtrace(int[] nums,int startindex){
//该算法为找子集,每一次遍历都可以输出添加
list.add(new ArrayList<>(sonlist));
if(sonlist.size() > nums.length)return;
for(int i = startindex;i < nums.length;i++){
// 核心代码在这一块细节
//通过大于下标以及如果两者相等,跳过该循环,此处不是大于 0
if(i > startindex && nums[i] == nums[i - 1])continue;
sonlist.addLast(nums[i]);
backtrace(nums,i + 1);
sonlist.removeLast();
}
}
}
排列
46. 全排列(中等)(不包含重复数字)
题目:
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]
提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同
思路:
这里和77.组合问题 、131.切割问题和78.子集问题
最大的不同就是for循环里不用startIndex了
因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。
排列问题总结
每层节点都是从0开始搜索而不是startindex
需要使用uded数组记录path放了哪些元素
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] flag = new boolean[nums.length];
backtrace(nums,flag);
return list;
}
public void backtrace(int[] nums,boolean[] flag){
// 对应全排列,只有全部满了,才可使用list添加
if(sonlist.size() == nums.length){
list.add(new ArrayList<>(sonlist));
}
// 此处不需要用index,也不需要提前排序
//每一层回溯遍历,都是从0开始,判断是否为true
// 1为true,在回溯的时候,1还是为true,则跳过1,来到了2。遍历完1 2 3类似这样子后。
for(int i = 0;i < nums.length;i++){
//如果这一层用了true的节点,则跳回
if(flag[i] == true)continue;
sonlist.addLast(nums[i]);
flag[i] = true;
backtrace(nums,flag);
flag[i] = false;
sonlist.removeLast();
}
}
}
47. 全排列 II(中等)
题目:
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
提示:
1 <= nums.length <= 8
-10 <= nums[i] <= 10
思路:
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
LinkedList<Integer> sonlist = new LinkedList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] flag = new boolean[nums.length];
Arrays.sort(nums);
backtrace(nums,flag);
return list;
}
public void backtrace(int[] nums,boolean[] flag){
// 对应全排列,只有全部满了,才可使用list添加
if(sonlist.size() == nums.length){
list.add(new ArrayList<>(sonlist));
}
// 此处不需要用index,也不需要提前排序
//每一层回溯遍历,都是从0开始,判断是否为true
// 1为true,在回溯的时候,1还是为true,则跳过1,来到了2。遍历完1 2 3类似这样子后。
for(int i = 0;i < nums.length;i++){
if(i > 0 && nums[i] == nums[i-1] && flag[i-1] == false)continue;
//如果这一层用了true的节点,则跳回
if(flag[i] == true)continue;
sonlist.addLast(nums[i]);
flag[i] = true;
backtrace(nums,flag);
flag[i] = false;
sonlist.removeLast();
}
}
}
补充
查重的时候一定要排序以及去重:
- 排序:
Arrays.sort(nums);
- 去重:
// 以下两者都可
if(i > 0 && nums[i] == nums[i-1] && flag[i-1] == false)continue;
if(i > 0 && nums[i] == nums[i-1] && flag[i-1] == true)continue;
其他
491. 递增子序列(中等)
题目:
给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
示例 1:
输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
示例 2:
输入:nums = [4,4,3,2,1]
输出:[[4,4]]
提示:
1 <= nums.length <= 15
-100 <= nums[i] <= 100
思路:
区别于上面其他思路:
因为原数组中不像之前的都是排序后在进行查重,所以不可使用之前的方法
在搜索遍历的时候就进行查重 而且 确定好排序
而且不可用上面思路中的标记数组
需要使用类似哈希表中的数组计数
注意题目中说了,数值范围[-100,100],所以完全可以用数组来做哈希
class Solution {
List<List<Integer>> list =new ArrayList<List<Integer>>();
List<Integer> sonlist=new ArrayList<>();
boolean [] flag;
public List<List<Integer>> findSubsequences(int[] nums) {
flag=new boolean [nums.length];
backtrace(nums,0);
return list;
}
public void backtrace(int [] nums,int startindex){
//确定列表的尺寸大于等于2才添加进去
if(sonlist.size()>=2){
list.add(new ArrayList<>(sonlist));
}
if(startindex>nums.length)return ;
int[] used = new int[201];
for(int i=startindex;i<nums.length;i++){
//因为原数组中不像之前的都是排序后在进行查重,所以不可使用之前的方法
//在搜索遍历的时候就进行查重 而且 确定好排序
if(!sonlist.isEmpty()&&nums[i]<sonlist.get(sonlist.size()-1) ||used[nums[i] + 100] == 1 )continue;
used[nums[i] + 100] = 1;
flag[i]=true;
sonlist.add(nums[i]);
backtrace(nums,i+1);
sonlist.remove(sonlist.size() - 1);
}
}
}
51. N 皇后(困难)*
题目:51. N 皇后
行、列、左斜、右斜
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> solutions = new ArrayList<List<String>>();
int[] queens = new int[n];
// 全部初始化为-1,此处不初始化都可,因为后面会把其覆盖
Arrays.fill(queens,-1);
// 区分皇后主要通过三个set集合,对应列,左斜,右斜。行的话,本身回溯就已经判断了
Set<Integer> column = new HashSet<>();
Set<Integer> left = new HashSet<>();
Set<Integer> right = new HashSet<>();
backtrace(solutions,queens,n,0,column,left,right);
return solutions;
}
// 传入整个list集合 queens的数组,对应矩阵n,以及row 行,之后就是各个集合
public void backtrace(List<List<String>> solutions,int[] queens,int n,int row,Set<Integer> column,Set<Integer> left,Set<Integer> right){
// 放置的皇后个数已经等于n了,将其拼接在一起
if(row == n){
List<String> list = new ArrayList<>();
// 具体拼接通过另外一个函数
list = generate(queens,n);
solutions.add(list);
}else {
// 遍历每一皇后的存储位置
for(int i = 0;i < n;i++){
// 一一对应判断是否有其值
if(column.contains(i)){
continue;
}
// 左斜是通过row - i,规律
int sonleft = row - i;
if(left.contains(sonleft)){
continue;
}
// 右斜是通过row + i,规律
int sonright = row + i;
if(right.contains(sonright)){
continue;
}
// 对应回溯,一开始赋值为i,主要是标记,后面拼接给予Q
queens[row] = i;
column.add(i);
left.add(sonleft);
right.add(sonright);
backtrace(solutions,queens,n,row + 1,column,left,right);
// 回溯结束赋值为原来的值
queens[row] = -1;
column.remove(i);
left.remove(sonleft);
right.remove(sonright);
}
}
}
public List<String> generate(int[] queens,int n){
List<String> list = new ArrayList<>();
for(int i = 0;i < n;i++){
// 每一行的 一个个拼接 覆盖
char[] row = new char[n];
// 赋值初始值
Arrays.fill(row,'.');
row[queens[i]] = 'Q';
// 最后list add的时候要通过new String构建对象
list.add(new String(row));
}
return list;
}
}
类似这道题的思路:
查看如下:52. N皇后 II(困难)
class Solution {
public int totalNQueens(int n) {
Set<Integer> column = new HashSet<>();
Set<Integer> left = new HashSet<>();
Set<Integer> right = new HashSet<>();
return backtrace(n,0,column,left,right);
}
public int backtrace(int n,int row,Set<Integer> column,Set<Integer> left,Set<Integer> right){
// 放置的皇后个数已经等于n了,直接返回1即可
if(row == n){
return 1;
}else {
// 个数统计 count
int count = 0;
for(int i = 0;i < n;i++){
if(column.contains(i)){
continue;
}
int sonleft = row - i;
if(left.contains(sonleft)){
continue;
}
int sonright = row + i;
if(right.contains(sonright)){
continue;
}
column.add(i);
left.add(sonleft);
right.add(sonright);
count += backtrace(n,row + 1,column,left,right);
column.remove(i);
left.remove(sonleft);
right.remove(sonright);
}
// 回溯提前结束,直接返回count的个数
return count;
}
}
}
37. 解数独(困难)
类似的题目如下,只不过下面这个题不是回溯,类似模拟算法
题目:leetcode:36. 有效的数独(中等)
class Solution {
public boolean isValidSudoku(char[][] board) {
// 每个数组大致都定义为 9行 或者 9列,最后的9为index 表示该元素+1
int[][] row = new int [9][9];
int[][] column = new int[9][9];
// box 3*3的表框,后面的9 为index 表示该元素+1
int[][][] box = new int[3][3][9];
for(int i = 0;i < 9;i++){
for(int j = 0;j < 9;j++){
// 取出该元素
char c = board[i][j];
if(c != '.'){
// 注意此处要多减去1,因为下标与位置相差1
int index = c - '0' - 1;
row[i][index]++;
column[j][index]++;
box[i / 3][j / 3][index]++;
if(row[i][index] > 1 || column[j][index] > 1 || box[i / 3][j / 3][index] > 1){
return false;
}
}
}
}
return true;
}
}