java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846
1. 暴力回溯
解题思路:时间复杂度O( n n n^n n n ),但是严格来说只到了O( n ∗ n ! n*n! n ∗ n ! ) 因为很多元素只进行了一个判断,没有执行其它操作,所以它们不会很耗费时间,如果把判断算上,则是n^n时间复杂度。空间复杂度O(n)
创建一个flag数组,boolean类型。标志当前数字是否被选过。 我们每个位置的数字枚举时,都先检查flag数组,如果当前数字为false,则可选。 直到所有数字枚举完成
class Solution { int [ ] nums; boolean [ ] numsFlag; int len; List < List < Integer > > ans = new ArrayList < List < Integer > > ( ) ; public List < List < Integer > > permute ( int [ ] nums) { this . nums = nums; this . len = nums. length; this . numsFlag = new boolean [ len] ; ArrayList < Integer > records = new ArrayList < > ( ) ; backTracking ( records) ; return ans; } public void backTracking ( List < Integer > records) { if ( records. size ( ) == len) ans. add ( new ArrayList < > ( records) ) ; else { for ( int i = 0 ; i< len; i++ ) { if ( this . numsFlag[ i] == false ) { this . numsFlag[ i] = true ; records. add ( nums[ i] ) ; backTracking ( records) ; this . numsFlag[ i] = false ; records. remove ( records. size ( ) - 1 ) ; } } } }
}
2. 分区法+回溯
解题思路:时间复杂度O( n ∗ n ! n*n! n ∗ n ! ),空间复杂度O(n)
将数组分为两个区域,用index下标分割,index左边保存当前已经选择的数字,右边保存剩余可选的数字 每次通过交换操作,将我们想要在这次选择的数字,移动到index位置,然后index++ 下个数字只能从index和index后面的位置选取。这样就自动跳过了已经选取过的数字。而不用flag数组进行额外的判断
class Solution { List < List < Integer > > ans = new ArrayList < > ( ) ; int [ ] nums; public List < List < Integer > > permute ( int [ ] nums) { this . nums = nums; backTracking ( 0 ) ; return ans; } public void backTracking ( int index) { if ( index == nums. length) { List < Integer > list = new ArrayList < > ( ) ; for ( int num : nums ) list. add ( num) ; ans. add ( list) ; } else { for ( int j = index; j < nums. length; j++ ) { swap ( nums, index, j) ; backTracking ( index + 1 ) ; swap ( nums, j, index) ; } } } private void swap ( int [ ] nums, int i, int j) { if ( i == j) return ; nums[ i] = nums[ i] ^ nums[ j] ; nums[ j] = nums[ i] ^ nums[ j] ; nums[ i] = nums[ i] ^ nums[ j] ; } }