給出集合 [1,2,3,…,n],其所有元素共有 n! 種排列。
按大小順序列出所有排列情況,並一一標記,當 n = 3 時, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
給定 n 和 k,返回第 k 個排列。
說明:
給定 n 的範圍是 [1, 9]。
給定 k 的範圍是[1, n!]。
示例 1:
輸入: n = 3, k = 3
輸出: "213"
示例 2:
輸入: n = 4, k = 9
輸出: "2314"
康託編碼
解題思路
採用康託編碼的思路。其實就是康託展開的逆過程。康託展開用來求某個全排列數是第幾小的數,也就是當這些數按順序排時第幾個數。
過程如下:比如求321 是 第幾小的,可以這樣來想:小於3的數有1和2 兩個,首位確定之後後面兩位有2!中情況,所以共有2*2!=4種。
小於2的數只有一個1,所以有11!=1種情況,最後一位是1,沒有比一小的數,所以是00!=0
綜上:小於321的數有4+1=5個,所以321是第六小的數。
逆過程就是已知這個數是第k個數,求這個數是多少,當然是知道n的值的。
第k個數就是有k-1個數比這個數小。
所以就是 k-1=an*(n-1)!+an-1*(n-2)!+....+a1*0!;
再舉一個例子:如何找出第16個(按字典序的){1,2,3,4,5}的全排列?
首先用16-1得到15
用15去除4! 得到0餘15
用15去除3! 得到2餘3
用3去除2! 得到1餘1
用1去除1! 得到1餘0
有0個數比它小的數是1,所以第一位是1
有2個數比它小的數是3,但1已經在之前出現過了所以是4
有1個數比它小的數是2,但1已經在之前出現過了所以是3
有1個數比它小的數是2,但1,3,4都出現過了所以是5
最後一個數只能是2
所以排列爲1 4 3 5 2
class Solution {
public:
string getPermutation(int n, int k) {
string s="123456789",res="";
if(k==1||n==1)return s.substr(0,n);
vector<int>nn(n);//n!
nn[0]=0;//0!
nn[1]=1;//1!
--k;
for(int i=2;i<n;++i)
nn[i]=i*nn[i-1];
for(int i=n-1;i>0;--i){
auto it=s.begin()+k/nn[i];//auto it=s.begin();advance(it,k/nn[i]);
k=k%nn[i];
res+=(*it);//res.push_back(*it);
s.erase(it);//!!!
}
res+=s[0];
return res;
}
};
給定一個 m x n 的矩陣,如果一個元素爲 0,則將其所在行和列的所有元素都設爲 0。請使用原地算法。
示例 1:
輸入:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
輸出:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
示例 2:
輸入:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
輸出:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]
進階:
一個直接的解決方案是使用 O(mn) 的額外空間,但這並不是一個好的解決方案。
一個簡單的改進方案是使用 O(m + n) 的額外空間,但這仍然不是最好的解決方案。
你能想出一個常數空間的解決方案嗎?
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
unordered_set<int>rowCol;//O(m+n)額外空間
int m=matrix.size();
if(m==0)return;
int n=matrix[0].size();
if(n==0)return;
for(int i=0;i<m;++i)
for(int j=0;j<n;++j)
if(matrix[i][j]==0)
rowCol.insert(i),rowCol.insert(m+j);
for(int i=0;i<m;++i)
for(int j=0;j<n;++j)
if(rowCol.count(i)||rowCol.count(m+j))
matrix[i][j]=0;
}
};
//matrix[0<=i<m][0]==0表示第i+1行應該置0
//matrix[0][1<=j<n]==0表示第j+1列應該置0;matrix00IsCol==true表示第1列應該置0
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m=matrix.size();
if(m==0)return;
int n=matrix[0].size();
if(n==0)return;
bool matrix00IsCol=false;//常數額外空間
for(int i=0;i<m;++i){
if(matrix[i][0]==0)matrix00IsCol=true;
for(int j=1;j<n;++j)//j=0出錯:[[1,1,1],[0,1,2]]
if(matrix[i][j]==0)
matrix[0][j]=0,matrix[i][0]=0;
}
for(int i=1;i<m;++i)//處理第2列~第n列 第2行~第m行應該置0的情況
for(int j=1;j<n;++j)
if(matrix[i][0]==0||matrix[0][j]==0)
matrix[i][j]=0;
if(matrix[0][0]==0)//處理第1行應該置0的情況
for(int j=1;j<n;++j)
matrix[0][j]=0;
if(matrix00IsCol)//處理第1列應該置0的情況
for(int i=0;i<m;++i)
matrix[i][0]=0;
}
};
編寫一個高效的算法來判斷 m x n 矩陣中,是否存在一個目標值。該矩陣具有如下特性:
每行中的整數從左到右按升序排列。
每行的第一個整數大於前一行的最後一個整數。
示例 1:
輸入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 3
輸出: true
示例 2:
輸入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 13
輸出: false
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m=matrix.size();
if(m==0)return false;
int n=matrix[0].size();
if(n==0)return false;
int le=0,ri=m*n-1;
while(le<=ri){
int mid=le+((ri-le)>>1);
int i=mid/n,j=mid%n;
if(target==matrix[i][j])return true;
else if(target<matrix[i][j])ri=mid-1;
else le=mid+1;
}
return false;
}
}
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重複的元素。
你的算法時間複雜度必須是 O(log n) 級別。
示例 1:
輸入: nums = [4,5,6,7,0,1,2], target = 0
輸出: 4
示例 2:
輸入: nums = [4,5,6,7,0,1,2], target = 3
輸出: -1
class Solution {
public:
int search(vector<int>& nums, int target) {
int le=0,ri=nums.size()-1;
while(le<=ri){
int mid=le+((ri-le)>>1);
if(nums[mid]==target)return mid;
if(nums[mid]>=nums[le])//[le~mid]有序
if(nums[le]<=target&&target<nums[mid])ri=mid-1;//判斷是否屬於有序部分,即大於等最小值&&小於等於最大值
else le=mid+1;
else//[mid~ri]有序
if(nums[mid]<target&&target<=nums[ri])le=mid+1;//判斷是否屬於有序部分,即大於等最小值&&小於等於最大值
else ri=mid-1;
}
return -1;
}
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,0,1,2,2,5,6] 可能變爲 [2,5,6,0,0,1,2] )。
編寫一個函數來判斷給定的目標值是否存在於數組中。若存在返回 true,否則返回 false。
示例 1:
輸入: nums = [2,5,6,0,0,1,2], target = 0
輸出: true
示例 2:
輸入: nums = [2,5,6,0,0,1,2], target = 3
輸出: false
進階:
這是 搜索旋轉排序數組 的延伸題目,本題中的 nums 可能包含重複元素。
這會影響到程序的時間複雜度嗎?會有怎樣的影響,爲什麼?
class Solution {
public:
bool search(vector<int>& nums, int target) {
int le=0,ri=nums.size()-1;
while(le<=ri){
int mid=le+((ri-le)>>1);
if(nums[mid]==target)return true;
//nums[mid]==nums[le]的情況判斷不出是[le-mid]還是[mid-ri]有序,所以要特殊處理,即+1直到不相等的情況出現爲止
while(le<=ri&&nums[mid]==nums[le])++le;
if(le>mid)continue;
if(nums[mid]>nums[le])//[le-mid]有序
if(nums[le]<=target&&target<nums[mid])ri=mid-1;
else le=mid+1;
else//[mid-ri]有序
if(nums[mid]<target&&target<=nums[ri])le=mid+1;
else ri=mid-1;
}
return false;
}
};