332. Reconstruct Itinerary
vector<string> res;
vector<string> findItinerary(vector<vector<string>>& tickets) {
res.push_back("JFK");
sort(tickets.begin(),tickets.end());
map<string,vector<string>> adj;
for (auto val:tickets) {
adj[val[0]].push_back(val[1]);
}
dfs("JFK",tickets.size(),adj);
return res;
}
bool dfs(const string& src,int target_length,map<string,vector<string>> adj){
if (res.size()==target_length+1){
return true;
}
if (adj.find(src)==adj.end()){
return false;
}
vector<string> copy(adj[src]);
for(int i=0;i<copy.size();i++){
string val=copy.at(i);
res.push_back(copy.at(i));
adj[src].erase(adj[src].begin()+i);
if (dfs(val,target_length,adj)){
return true;
}
res.pop_back();
adj[src].insert(adj[src].begin()+i,val);
}
return false;
}
*334. Increasing Triplet Subsequence
bool increasingTriplet(vector<int>& nums) {
int n = nums.size(), ans = 1;
vector<int> f(n + 1, INT_MAX);
for(int i = 0; i < n; i++){
int t = nums[i];
int L = 1, R = i + 1;
while(L < R){
int mid = (L + R) >> 1;
if(f[mid] >= t) R = mid;
else L = mid + 1;
}
f[R] = t;
ans = max(ans, R);
}
return ans >= 3;
}
简单来说,就是在遍历每个数 nums[i] 的同时,维护一个具有单调性的 f[] 数组,其中 f[len]=x 代表长度为 len 的最长上升子序列最小结尾元素为 x,可以证明 f 数组具有单调性(看 前置🧀),因此每次可以通过二分找到小于 nums[i] 的最大下标,来作为 nums[i] 的前一个数。
338. Counting Bits
vector<int> countBits(int n) {
vector<int> res(n+1,0);
res[0]=0;
if (n==0){
return res;
}
res[1]=1;
int i=2;
int length=2;
while(i+length<=n){
for(int j=0;j<length;j++){
res[i+j]=res[i+j-length]+1;
}
i+=length;
length*=2;
}
for (int j = i; j <=n ; ++j) {
res[j]=res[j-length]+1;
}
return res;
}
*342. Power of Four
bool isPowerOfFour(int n) {
return n > 0 && (n & (n - 1)) == 0 && n % 3 == 1;
}
343. Integer Break
递归解法(19以上会超时)
class Solution {
public static int totalInteger;
public int integerBreak(int n) {
totalInteger=n;
return dfs(n);
}
public int dfs(int num){
int res;
if(totalInteger==num){
res=0;
}
else{
res=num;
}
if(num==1){
return 1;
}
for(int i=1;i<num;i++){
res = Math.max(dfs(i)*dfs(num-i),res);
}
return res;
}
}
动态规划解法
public int integerBreak(int n) {
if(n==1){
return 1;
}
int[] dp=new int[n+1];
dp[1]=1;
for(int i=2;i<=n;i++){
if(i==n){
dp[i]=0;
}
else{
dp[i]=i;
}
for(int j=1;j<i;j++){
dp[i]=Math.max(dp[j]*dp[i-j],dp[i]);
}
}
return dp[n];
}
数学方法
原网址:https://math.stackexchange.com/questions/1860096/maximize-the-product-of-the-partitions-of-an-integer
对于:
n
=
x
1
+
x
2
+
.
.
.
+
x
k
n=x_1+x_2+...+x_k
n=x1+x2+...+xk
令
S
(
n
)
=
∏
i
=
1
k
x
i
S(n)=\prod_{i=1}^{k} x_i
S(n)=i=1∏kxi
对两边取
ln
(
)
\ln()
ln()得:
ln
S
(
n
)
=
∑
i
=
1
k
ln
x
i
\ln S(n)=\sum_{i=1}^{k} \ln x_i
lnS(n)=i=1∑klnxi
我们知道,对于给定数
m
m
m,
x
i
+
x
2
=
m
x_i+x_2=m
xi+x2=m求最大的
x
1
∗
x
2
x_1*x_2
x1∗x2当且仅当
x
1
=
x
2
=
m
/
2
x_1=x_2=m/2
x1=x2=m/2时取得。
因此我们可以令:
x
=
x
1
=
x
2
=
.
.
.
x
k
x=x_1=x_2=...x_k
x=x1=x2=...xk:
那么原式转化为:
ln
S
(
n
)
=
k
∗
ln
x
k
\ln S(n)=k* \ln{ \frac{x}{k}}
lnS(n)=k∗lnkx
对
k
k
k求导得:
ln
x
k
=
1
\ln{ \frac{x}{k}} = 1
lnkx=1
因此当
x
/
k
=
1
x/k=1
x/k=1即
k
≈
3
k \approx 3
k≈3时取得最大值。
public int integerBreak(int n) {
if(n==2){
return 1;
}
if(n==3){
return 2;
}
int times=n/3;
int residual=n%3;
if(residual<2){
return(int)Math.pow(3,times-1)*(residual+3);
}
else{
return(int)Math.pow(3,times)*(residual);
}
}
344. Reverse String
Stack
void reverseString(vector<char>& s) {
stack<char> stack1;
for(char ch: s){
stack1.push(ch);
}
for (char & i : s) {
i=stack1.top();
stack1.pop();
}
}
Swap
void reverseString(vector<char>& s) {
int start=0;
int end=s.size()-1;
while(start<end){
char tmp=s[start];
s[start]=s[end];
s[end]=tmp;
start++;
end--;
}
}
345. Reverse Vowels of a String
string reverseVowels(string s) {
int left=0;
int right=s.size()-1;
vector<bool> vowel(256, false);
vowel['a']=true;
vowel['i']=true;
vowel['u']=true;
vowel['e']=true;
vowel['o']=true;
vowel['A']=true;
vowel['I']=true;
vowel['U']=true;
vowel['E']=true;
vowel['O']=true;
while(left<right){
while(left<right&&!vowel[s[left]]){
left++;
}
while (left<right&&!vowel[s[right]]){
right--;
}
char tmp=s[left];
s[left]=s[right];
s[right]=tmp;
left++;
right--;
}
return s;
}
347. Top K Frequent Elements
反向映射次数HashMap
class Solution {
public int[] topKFrequent(int[] nums, int k) {
ArrayList<Integer> res = new ArrayList<>();
HashMap<Integer, Integer> occurrence = new HashMap<>();
HashMap<Integer, ArrayList<Integer>> occurrenceReversed = new HashMap<>(nums.length);
for (var val : nums) {
occurrence.put(val, occurrence.getOrDefault(val, 0) + 1);
}
for (var entry : occurrence.entrySet()) {
if (!occurrenceReversed.containsKey(entry.getValue())) {
occurrenceReversed.put(entry.getValue(), new ArrayList<>());
occurrenceReversed.get(entry.getValue()).add(entry.getKey());
} else {
occurrenceReversed.get(entry.getValue()).add(entry.getKey());
}
}
int curr = nums.length;
while (k > 0) {
if (occurrenceReversed.containsKey(curr)) {
for (var val : occurrenceReversed.get(curr)) {
res.add(val);
k--;
if (k == 0) {
return res.stream().mapToInt(i -> i).toArray();
}
}
}
curr--;
}
return res.stream().mapToInt(i -> i).toArray();
}
}
349. Intersection of Two Arrays(Solved)
使用流
public int[] intersection(int[] nums1, int[] nums2) {
HashSet<Integer> distinct1=new HashSet<>();
for (var val:nums1){
distinct1.add(val);
}
ArrayList<Integer> res=new ArrayList<>();
for (var val:nums2){
if (distinct1.contains(val)){
res.add(val);
distinct1.remove(val);
}
}
return res.stream().mapToInt(i->i).toArray();
}
普遍遍历,速度更快(-50%)
public int[] intersection(int[] nums1, int[] nums2) {
HashSet<Integer> distinct1=new HashSet<>();
for (var val:nums1){
distinct1.add(val);
}
ArrayList<Integer> res=new ArrayList<>();
for (var val:nums2){
if (distinct1.contains(val)){
res.add(val);
distinct1.remove(val);
}
}
int[] intRes=new int[res.size()];
for (int i=0;i< res.size();i++){
intRes[i]=res.get(i);
}
return intRes;
// return res.stream().mapToInt(i->i).toArray();
}
350. Intersection of Two Arrays II
public int[] intersect(int[] nums1, int[] nums2) {
int[] dict=new int[1001];
for (int val:nums1){
dict[val]++;
}
ArrayList<Integer> res=new ArrayList<>(1000);
for (int val:nums2){
if (dict[val]>0){
res.add(val);
dict[val]--;
}
}
int[] resArr=new int[res.size()];
for (int i=0;i<res.size();i++){
resArr[i]=res.get(i);
}
return resArr;
}
* 354. Russian Doll Envelopes
Solution
这道题的解法是比较巧妙的:
先对宽度 w
进行升序排序,如果遇到 w
相同的情况,则按照高度 h
降序排序。之后把所有的 h
作为一个数组,在这个数组上计算 LIS 的长度就是答案。
画个图理解一下,先对这些数对进行排序:
然后在 h 上寻找最长递增子序列:
这个子序列就是最优的嵌套方案。
这个解法的关键在于,对于宽度 w
相同的数对,要对其高度 h
进行降序排序。因为两个宽度相同的信封不能相互包含的,逆序排序保证在w
相同的数对中最多只选取一个。
Half Correct
public int maxEnvelopes(int[][] envelopes) {
Arrays.sort(envelopes,(a,b)->{
if (a[0]!=b[0]){
return a[0]-b[0];
}
return b[1]-a[1];
});
int[] height=new int[envelopes.length];
for (int i=0;i<envelopes.length;i++){
height[i]=envelopes[i][1];
}
return lengthOfLis(height);
}
public int lengthOfLis(int[] arr){
int[] longest=new int[arr.length];
Arrays.fill(longest,1);
int longestVal=1;
for(int i=1;i<arr.length;i++){
for (int j=0;j<i;j++){
if (arr[i]>arr[j]){
longest[i]=Math.max(longest[i],1+longest[j]);
}
}
longestVal=Math.max(longestVal,longest[i]);
}
return longestVal;
}
Revised LIS
public int maxEnvelopes(int[][] envelopes) {
Arrays.sort(envelopes,(a,b)->{
if (a[0]!=b[0]){
return a[0]-b[0];
}
return b[1]-a[1];
});
int[] height=new int[envelopes.length];
for (int i=0;i<envelopes.length;i++){
height[i]=envelopes[i][1];
}
return lengthOfLIS(height);
}
public int lengthOfLIS(int[] nums) {
int piles = 0, n = nums.length;
int[] top = new int[n];
for (int i = 0; i < n; i++) {
// 要处理的扑克牌
int poker = nums[i];
int left = 0, right = piles;
// 二分查找插入位置
while (left < right) {
int mid = (left + right) / 2;
if (top[mid] >= poker)
right = mid;
else
left = mid + 1;
}
if (left == piles) piles++;
// 把这张牌放到牌堆顶
top[left] = poker;
}
// 牌堆数就是 LIS 长度
return piles;
}
357. Count Numbers with Unique Digits
public int countNumbersWithUniqueDigits(int n) {
if (n == 0) {
return 1;
}
int ways = 10;
if (n == 1) {
return ways;
}
for (int i = 2; i <= n; i++) {
// ways+=selectWays(9,1)* selectWays(9,n-1)*permutations(i-1);
ways += 9 * permutations2(9, i - 1);
}
return ways;
}
public int selectWays(int n, int c) {
if (c == 0) {
return 0;
}
int base = n;
for (int i = n - 1; i > n - c; i--) {
base *= i;
}
int factor = c;
for (int i = c - 1; i > 1; i--) {
factor *= i;
}
return base / factor;
}
public int permutations(int n) {
int res = n;
for (int i = n - 1; i > 1; i--) {
res *= i;
}
return res;
}
public int permutations2(int n, int c) {
int res = n;
for (int i = n - 1; i > n - c; i--) {
res *= i;
}
return res;
}