Leetcode劍指offer(八)
Leetcode劍指offer
61、和為s的連續正數序列(57-2、Easy)
1)題目要求
輸入一個正整數 target ,輸出所有和為 target 的連續正整數序列(至少含有兩個數)。
序列內的數字由小到大排列,不同序列按照首個數字從小到大排列。
示例 1:
輸入:target = 9
輸出:[[2,3,4],[4,5]]
示例 2:
輸入:target = 15
輸出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
2)我的解法
1、超時
class Solution {
public int[][] findContinuousSequence(int target) {
double sum=0;
int l=0,r=0;
List<int[]> temp=new ArrayList<>();
for(int i=1;i<target/2+1;i++){
l=i;
r=target/2+1;
while(l<r){
sum=(l+r)*(r-l+1)/2.0;
if(sum==target){
int[] tem=new int[r-l+1];
int index=0;
for(int k=l;k<=r;k++)tem[index++]=k;
temp.add(tem);
break;
}
else if(sum>target)r--;
else break;
}
}
int[][] res=new int[temp.size()][];
int index=0;
for(int[] shuzu:temp){
res[index++]=shuzu;
}
return res;
}
}
2、滑動視窗
class Solution {
public int[][] findContinuousSequence(int target) {
double sum=0;
int l=1,r=2;
List<int[]> temp=new ArrayList<>();
for(int i=1;i<target/2+1;i++){
l=i;
while(l<r){
sum=(l+r)*(r-l+1)/2.0;
if(sum==target){
int[] tem=new int[r-l+1];
int index=0;
for(int k=l;k<=r;k++)tem[index++]=k;
temp.add(tem);
r++;
break;
}
else if(sum<target)r++;
else break;
}
}
int[][] res=new int[temp.size()][];
int index=0;
for(int[] shuzu:temp){
res[index++]=shuzu;
}
return res;
}
}
3)其他解法
1、
public int[][] findContinuousSequence(int target) {
int i = 1; // 滑動視窗的左邊界
int j = 1; // 滑動視窗的右邊界
int sum = 0; // 滑動視窗中數字的和
List<int[]> res = new ArrayList<>();
while (i <= target / 2) {
if (sum < target) {
// 右邊界向右移動
sum += j;
j++;
} else if (sum > target) {
// 左邊界向右移動
sum -= i;
i++;
} else {
// 記錄結果
int[] arr = new int[j-i];
for (int k = i; k < j; k++) {
arr[k-i] = k;
}
res.add(arr);
// 左邊界向右移動
sum -= i;
i++;
}
}
return res.toArray(new int[res.size()][]);
}
作者:nettee
連結:link
來源:力扣(LeetCode)
2、數學解法
減1,看能不能分成兩個數
減2,看能不能分成3個數,
以此類推
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> result = new ArrayList<>();
int i = 1;
while(target>0)
{
target -= i++;
if(target>0 && target%i == 0)
{
int[] array = new int[i];
for(int k = target/i, j = 0; k < target/i+i; k++,j++)
{
array[j] = k;
}
result.add(array);
}
}
Collections.reverse(result);
return result.toArray(new int[0][]);
}
}
作者:VaporMax
連結:link
來源:力扣(LeetCode)
4)自己的優化程式碼
class Solution {
public int[][] findContinuousSequence(int target) {
double sum=0;
int l=1,r=2;
List<int[]> temp=new ArrayList<>();
while(l<target/2+1){
sum=(l+r)*(r-l+1)/2.0;
if(sum==target){
int[] tem=new int[r-l+1];
int index=0;
for(int k=l;k<=r;k++)tem[index++]=k;
temp.add(tem);
l++;r++;
}
else if(sum<target)r++;
else l++;
}
return temp.toArray(new int[temp.size()][]);
}
}
5)學到的東西
滑動視窗
62、翻轉單詞順序(58-1、Easy)
1)題目要求
輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字元的順序不變。為簡單起見,標點符號和普通字母一樣處理。例如輸入字串"I am a student. “,則輸出"student. a am I”。
示例 1:
輸入: “the sky is blue”
輸出: “blue is sky the”
示例 2:
輸入: " hello world! "
輸出: “world! hello”
解釋: 輸入字串可以在前面或者後面包含多餘的空格,但是反轉後的字元不能包括。
示例 3:
輸入: “a good example”
輸出: “example good a”
解釋: 如果兩個單詞間有多餘的空格,將反轉後單詞間的空格減少到只含一個。
說明:
無空格字元構成一個單詞。
輸入字串可以在前面或者後面包含多餘的空格,但是反轉後的字元不能包括。
如果兩個單詞間有多餘的空格,將反轉後單詞間的空格減少到只含一個。
2)我的解法
class Solution {
public String reverseWords(String s) {
String[] words=s.split("\\s+");
StringBuilder sb=new StringBuilder();
for(int i=words.length-1;i>=0;i--)sb.append(words[i]+" ");
return sb.toString().trim();
}
}
3)其他解法
1、
class Solution {
public String reverseWords(String s) {
s = s.trim(); // 刪除首尾空格
int j = s.length() - 1, i = j;
StringBuilder res = new StringBuilder();
while(i >= 0) {
while(i >= 0 && s.charAt(i) != ' ') i--; // 搜尋首個空格
res.append(s.substring(i + 1, j + 1) + " "); // 新增單詞
while(i >= 0 && s.charAt(i) == ' ') i--; // 跳過單詞間空格
j = i; // j 指向下個單詞的尾字元
}
return res.toString().trim(); // 轉化為字串並返回
}
}
2、
class Solution {
public String reverseWords(String s) {
String[] strs = s.trim().split(" "); // 刪除首尾空格,分割字串
StringBuilder res = new StringBuilder();
for(int i = strs.length - 1; i >= 0; i--) { // 倒序遍歷單詞列表
if(strs[i].equals("")) continue; // 遇到空單詞則跳過
res.append(strs[i] + " "); // 將單詞拼接至 StringBuilder
}
return res.toString().trim(); // 轉化為字串,刪除尾部空格,並返回
}
}
作者:jyd
連結: link
來源:力扣(LeetCode)
4)自己的優化程式碼
1、
class Solution {
public String reverseWords(String s) {
StringBuilder sb=new StringBuilder();
int i=s.length()-1,j=s.length()-1;
while(i>=0&&j>=0){
while(j>=0&&s.charAt(j)==' ')j--;
if(j<0)break;
i=j;
while(i>=0&&s.charAt(i)!=' ')i--;
sb.append(" "+s.substring(i+1,j+1));
j=i;
}
return sb.toString().trim();
}
}
2、
class Solution {
public String reverseWords(String s) {
String[] words = s.split(" ");
StringBuilder sb = new StringBuilder();
for(int i = words.length - 1; i >= 0; i--){
if(words[i].equals("")) continue;
sb.append(words[i]).append(" ");
}
return sb.toString().trim();
}
}
5)學到的東西
s.substring(start,end) [start,end)
split中的正規表示式越複雜,效率越低
63、左旋轉字串(58-2、Easy)
1)題目要求
字串的左旋轉操作是把字串前面的若干個字元轉移到字串的尾部。請定義一個函式實現字串左旋轉操作的功能。比如,輸入字串"abcdefg"和數字2,該函式將返回左旋轉兩位得到的結果"cdefgab"。
示例 1:
輸入: s = “abcdefg”, k = 2
輸出: “cdefgab”
示例 2:
輸入: s = “lrloseumgh”, k = 6
輸出: “umghlrlose”
限制:
1 <= k < s.length <= 10000
2)我的解法
1、
class Solution {
public String reverseLeftWords(String s, int n) {
return s.substring(n,s.length())+s.substring(0,n);
}
}
2、
class Solution {
public String reverseLeftWords(String s, int n) {
return (s+s).substring(n,s.length()+n);
}
}
3)其他解法
1、StringBuilder
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder res = new StringBuilder();
for(int i = n; i < s.length(); i++)
res.append(s.charAt(i));
for(int i = 0; i < n; i++)
res.append(s.charAt(i));
return res.toString();
}
}
利用求餘運算,可以簡化程式碼。
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder res = new StringBuilder();
for(int i = n; i < n + s.length(); i++)
res.append(s.charAt(i % s.length()));
return res.toString();
}
}
2、只能用String的話
class Solution {
public String reverseLeftWords(String s, int n) {
String res = "";
for(int i = n; i < s.length(); i++)
res += s.charAt(i);
for(int i = 0; i < n; i++)
res += s.charAt(i);
return res;
}
}
利用求餘運算,可以簡化程式碼。
class Solution {
public String reverseLeftWords(String s, int n) {
String res = "";
for(int i = n; i < n + s.length(); i++)
res += s.charAt(i % s.length());
return res;
}
}
作者:jyd
連結:link
來源:力扣(LeetCode)
4)自己的優化程式碼
class Solution {
public String reverseLeftWords(String s, int n) {
return (s+s).substring(n,s.length()+n);
}
}
效率:substring> stringbuilder> +
5)學到的東西
substring原始碼
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
64、滑動視窗的最大值(59-1、Easy)
1)題目要求
給定一個陣列 nums 和滑動視窗的大小 k,請找出所有滑動視窗裡的最大值。
示例:
輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
輸出: [3,3,5,5,6,7]
解釋:
滑動視窗的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
提示:
你可以假設 k 總是有效的,在輸入陣列不為空的情況下,1 ≤ k ≤ 輸入陣列的大小。
2)我的解法
1、暴力
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==0)return new int[0];
int[] result=new int[nums.length-k+1];
int i=0;
while(i<nums.length-k+1){
result[i]=Integer.MIN_VALUE;
for(int j=i;j<k+i;j++)result[i]=Math.max(result[i],nums[j]);
i++;
}
return result;
}
}
3)其他解法
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length == 0 || k == 0) return new int[0];
Deque<Integer> deque = new LinkedList<>();
int[] res = new int[nums.length - k + 1];
for(int j = 0, i = 1 - k; j < nums.length; i++, j++) {
if(i > 0 && deque.peekFirst() == nums[i - 1])
deque.removeFirst(); // 刪除 deque 中對應的 nums[i-1]
while(!deque.isEmpty() && deque.peekLast() < nums[j])
deque.removeLast(); // 保持 deque 遞減
deque.addLast(nums[j]);
if(i >= 0)
res[i] = deque.peekFirst(); // 記錄視窗最大值
}
return res;
}
}
可以將 “未形成視窗” 和 “形成視窗後” 兩個階段拆分到兩個迴圈裡實現。程式碼雖變長,但減少了冗餘的判斷操作。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length == 0 || k == 0) return new int[0];
Deque<Integer> deque = new LinkedList<>();
int[] res = new int[nums.length - k + 1];
for(int i = 0; i < k; i++) { // 未形成視窗
while(!deque.isEmpty() && deque.peekLast() < nums[i])
deque.removeLast();
deque.addLast(nums[i]);
}
res[0] = deque.peekFirst();
for(int i = k; i < nums.length; i++) { // 形成視窗後
if(deque.peekFirst() == nums[i - k])
deque.removeFirst();
while(!deque.isEmpty() && deque.peekLast() < nums[i])
deque.removeLast();
deque.addLast(nums[i]);
res[i - k + 1] = deque.peekFirst();
}
return res;
}
}
作者:jyd
連結: link
來源:力扣(LeetCode)
4)自己的優化程式碼
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==0)return new int[0];
int[] result=new int[nums.length-k+1];
Deque<Integer> de=new LinkedList<>();
for(int i=0;i<k;i++){//第一個視窗
while(!de.isEmpty()&&de.peekLast()<nums[i])de.removeLast();
de.offerLast(nums[i]);
}
result[0]=de.peekFirst();
for(int i=k;i<nums.length;i++){//之後的視窗
if(de.peekFirst()==nums[i-k])de.removeFirst();//如果之前那個視窗的最大值在視窗的最左邊,則把它去掉
while(!de.isEmpty()&&de.peekLast()<nums[i])de.removeLast();
de.offerLast(nums[i]);
result[i-k+1]=de.peekFirst();//deque永遠降序,則最大值永遠在第一個
}
return result;
}
}
5)學到的東西
雙端佇列、單調佇列,保持佇列降序
多刷幾遍
65、佇列的最大值(59-2、Medium)
1)題目要求
請定義一個佇列並實現函式 max_value 得到佇列裡的最大值,要求函式max_value、push_back 和 pop_front 的均攤時間複雜度都是O(1)。
若佇列為空,pop_front 和 max_value 需要返回 -1
示例 1:
輸入:
[“MaxQueue”,“push_back”,“push_back”,“max_value”,“pop_front”,“max_value”]
[[],[1],[2],[],[],[]]
輸出: [null,null,null,2,1,2]
示例 2:
輸入:
[“MaxQueue”,“pop_front”,“max_value”]
[[],[],[]]
輸出: [null,-1,-1]
限制:
1 <= push_back,pop_front,max_value的總運算元 <= 10000
1 <= value <= 10^5
2)我的解法
class MaxQueue {
Queue<Integer> q=new LinkedList<>();
Deque<Integer> de=new LinkedList<>();//單調佇列
public MaxQueue() {
}
public int max_value() {
return de.isEmpty()?-1:de.peekFirst();
}
public void push_back(int value) {
while(!de.isEmpty()&&de.peekLast()<value)de.pollLast();
de.offerLast(value);
q.offer(value);
}
public int pop_front() {
if(q.isEmpty())return -1;
if(q.peek().equals(de.peekFirst()))de.pollFirst();//因為佇列中存的為Integer,不能用==
return q.poll();
}
}
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue obj = new MaxQueue();
* int param_1 = obj.max_value();
* obj.push_back(value);
* int param_3 = obj.pop_front();
*/
3)其他解法
class MaxQueue {
Queue<Integer> q;
Deque<Integer> d;
public MaxQueue() {
q = new LinkedList<Integer>();
d = new LinkedList<Integer>();
}
public int max_value() {
if (d.isEmpty()) {
return -1;
}
return d.peekFirst();
}
public void push_back(int value) {
while (!d.isEmpty() && d.peekLast() < value) {
d.pollLast();
}
d.offerLast(value);
q.offer(value);
}
public int pop_front() {
if (q.isEmpty()) {
return -1;
}
int ans = q.poll();
if (ans == d.peekFirst()) {
d.pollFirst();
}
return ans;
}
}
作者:LeetCode-Solution
連結:link
來源:力扣(LeetCode)
4)自己的優化程式碼
class MaxQueue {
Queue<Integer> q=new LinkedList<>();
Deque<Integer> de=new LinkedList<>();//單調佇列
public MaxQueue() {
}
public int max_value() {
return de.isEmpty()?-1:de.peekFirst();
}
public void push_back(int value) {
while(!de.isEmpty()&&de.peekLast()<value)de.pollLast();
de.offerLast(value);
q.offer(value);
}
public int pop_front() {
if(q.isEmpty())return -1;
if(q.peek().equals(de.peekFirst()))de.pollFirst();//因為佇列中存的為Integer,不能用==
return q.poll();
}
}
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue obj = new MaxQueue();
* int param_1 = obj.max_value();
* obj.push_back(value);
* int param_3 = obj.pop_front();
*/
5)學到的東西
雙端佇列,單調佇列找最大值
66、n個骰子的點數(60、Easy)
1)題目要求
把n個骰子扔在地上,所有骰子朝上一面的點數之和為s。輸入n,列印出s的所有可能的值出現的概率。
你需要用一個浮點數陣列返回答案,其中第 i 個元素代表這 n 個骰子所能擲出的點數集合中第 i 小的那個的概率。
示例 1:
輸入: 1
輸出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]
示例 2:
輸入: 2
輸出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]
限制:
1 <= n <= 11
2)我的解法
動態規劃
class Solution {
public double[] twoSum(int n) {
double base=Math.pow((1.0/6.0),n);
int[][] dp=new int[n+1][6*n+1];//dp[i][j]即i個骰子投出和為j的可能的方案數
for(int i=1;i<=6;i++)dp[1][i]=1;//一個骰子的情況下,1-6均只有一種情況
for(int i=2;i<=n;i++){
for(int j=i;j<=i*6;j++){
for(int k=1;k<=6;k++){
if(j-k>=i-1&&j-k<=(i-1)*6)dp[i][j]+=dp[i-1][j-k];//dp[i-1][j-k]和dp[0][k]搭配
}
}
}
double[] res=new double[6*n-n+1];
for(int i=n;i<=6*n;i++){
res[i-n]=dp[n][i]*base;
}
return res;
}
}
3)其他解法
class Solution {
public:
vector<double> twoSum(int n) {
int dp[15][70];
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= 6; i ++) {
dp[1][i] = 1;
}
for (int i = 2; i <= n; i ++) {
for (int j = i; j <= 6*i; j ++) {
for (int cur = 1; cur <= 6; cur ++) {
if (j - cur <= 0) {
break;
}
dp[i][j] += dp[i-1][j-cur];
}
}
}
int all = pow(6, n);
vector<double> ret;
for (int i = n; i <= 6 * n; i ++) {
ret.push_back(dp[n][i] * 1.0 / all);
}
return ret;
}
};
class Solution {
public:
vector<double> twoSum(int n) {
int dp[70];
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= 6; i ++) {
dp[i] = 1;
}
for (int i = 2; i <= n; i ++) {
for (int j = 6*i; j >= i; j --) {
dp[j] = 0;
for (int cur = 1; cur <= 6; cur ++) {
if (j - cur < i-1) {
break;
}
dp[j] += dp[j-cur];
}
}
}
int all = pow(6, n);
vector<double> ret;
for (int i = n; i <= 6 * n; i ++) {
ret.push_back(dp[i] * 1.0 / all);
}
return ret;
}
};
作者:huwt
連結:link
來源:力扣(LeetCode)
4)自己的優化程式碼
class Solution {
public double[] twoSum(int n) {
double base=Math.pow((1.0/6.0),n);
//int[][] dp=new int[n+1][6*n+1];//dp[i][j]即i個骰子投出和為j的可能的方案數
int[] dp=new int[6*n+1];
for(int i=1;i<=6;i++)dp[i]=1;
for(int i=2;i<=n;i++){
for(int j=6*i;j>=i;j--){//j從大到小
dp[j]=0;
for(int k=1;k<=6;k++){
if(j-k>=i-1&&j-k<=(i-1)*6)dp[j]+=dp[j-k];//dp[i-1][j-k]和dp[0][k]搭配
}
}
}
double[] res=new double[6*n-n+1];
for(int i=n;i<=6*n;i++){
res[i-n]=dp[i]*base;
}
return res;
}
}
5)學到的東西
動態規劃
空間優化:(從大到小)
67、撲克牌中的順子(61、Easy)
1)題目要求
從撲克牌中隨機抽5張牌,判斷是不是一個順子,即這5張牌是不是連續的。2~10為數字本身,A為1,J為11,Q為12,K為13,而大、小王為 0 ,可以看成任意數字。A 不能視為 14。
示例 1:
輸入: [1,2,3,4,5]
輸出: True
示例 2:
輸入: [0,0,1,2,5]
輸出: True
限制:
陣列長度為 5
陣列的數取值為 [0, 13] .
2)我的解法
class Solution {
public boolean isStraight(int[] nums) {
Map<Integer,Integer> hash=new HashMap<>();
int start=14;
for(int i=0;i<nums.length;i++){
if(nums[i]==0){
if(!hash.containsKey(0))hash.put(0,1);
else hash.put(0,hash.get(0)+1);
}
else {
if(nums[i]<start)start=nums[i];
hash.put(nums[i],1);
}
}
for(int i=1;i<5;i++){
if(hash.containsKey(start+i))continue;
else{
if(hash.containsKey(0)&&hash.get(0)>0)hash.put(0,hash.get(0)-1);
else return false;
}
}
return true;
}
}
3)其他解法
class Solution {
public boolean isStraight(int[] nums) {
Set<Integer> repeat = new HashSet<>();
int max = 0, min = 14;
for(int num : nums) {
if(num == 0) continue; // 跳過大小王
max = Math.max(max, num); // 最大牌
min = Math.min(min, num); // 最小牌
if(repeat.contains(num)) return false; // 若有重複,提前返回 false
repeat.add(num); // 新增此牌至 Set
}
return max - min < 5; // 最大牌 - 最小牌 < 5 則可構成順子
}
}
class Solution {
public boolean isStraight(int[] nums) {
int joker = 0;
Arrays.sort(nums); // 陣列排序
for(int i = 0; i < 4; i++) {
if(nums[i] == 0) joker++; // 統計大小王數量
else if(nums[i] == nums[i + 1]) return false; // 若有重複,提前返回 false
}
return nums[4] - nums[joker] < 5; // 最大牌 - 最小牌 < 5 則可構成順子
}
}
作者:jyd
連結: link
來源:力扣(LeetCode)
4)自己的優化程式碼
1、
class Solution {
public boolean isStraight(int[] nums) {
Arrays.sort(nums);
int joker=0;
for(int i=0;i<nums.length;i++){
if(nums[i]==0)joker++;
else if(i>0&&nums[i]==nums[i-1])return false;
}
return nums[4]-nums[joker]<5;
}
}
2、
class Solution {
public boolean isStraight(int[] nums) {
Set<Integer> set=new HashSet<>();
int max=0,min=14;
for(int i=0;i<nums.length;i++){
if(nums[i]==0)continue;
if(set.contains(nums[i]))return false;
if(nums[i]>max)max=nums[i];
if(nums[i]<min)min=nums[i];
set.add(nums[i]);
}
return max-min<5;
}
}
5)學到的東西
思想:不重複且max-min<5的 ==順子
68、 圓圈中最後剩下的數字(62、Easy)
1)題目要求
0,1,n-1這n個數字排成一個圓圈,從數字0開始,每次從這個圓圈裡刪除第m個數字。求出這個圓圈裡剩下的最後一個數字。
例如,0、1、2、3、4這5個數字組成一個圓圈,從數字0開始每次刪除第3個數字,則刪除的前4個數字依次是2、0、4、1,因此最後剩下的數字是3。
示例 1:
輸入: n = 5, m = 3
輸出: 3
示例 2:
輸入: n = 10, m = 17
輸出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
2)我的解法
1、暴力(超時)
class Solution {
public int lastRemaining(int n, int m) {
if(m==1)return n-1;
Node cur=new Node(0);
Node head=cur;
int i=1;
while(i<n){
cur.next=new Node(i++);
cur=cur.next;
}
cur.next=head;
cur=head;
while(cur.next!=cur){
for(int j=1;j<m-1;j++)cur=cur.next;
cur.next=cur.next.next;
cur=cur.next;
}
return cur.val;
}
}
class Node{
int val;
Node next;
Node(int data){
this.val=data;
}
}
3)其他解法
1、
class Solution {
public int lastRemaining(int n, int m) {
ArrayList<Integer> list = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
list.add(i);
}
int idx = 0;
while (n > 1) {
idx = (idx + m - 1) % n;
list.remove(idx);
n--;
}
return list.get(0);
}
}
2、
class Solution {
public int lastRemaining(int n, int m) {
int ans = 0;
// 最後一輪剩下2個人,所以從2開始反推
for (int i = 2; i <= n; i++) {
ans = (ans + m) % i;
}
return ans;
}
}
作者:sweetieeyi
連結:link
來源:力扣(LeetCode)
4)自己的優化程式碼
1、
class Solution {
public int lastRemaining(int n, int m) {
List<Integer> list=new ArrayList<>();
for(int i=0;i<n;i++)list.add(i);
int index=0;
while(n>1){
index=(index+m-1)%n;
list.remove(index);
n--;
}
return list.get(0);
}
}
2、數學方法
class Solution {
public int lastRemaining(int n, int m) {
int ans=0;
for(int i=2;i<=n;i++)ans=(ans+m)%i;
return ans;
}
}
5)學到的東西
利用陣列,降低刪除的時間消耗
找規律
多刷幾遍
69、股票的最大利潤(63、Medium)
1)題目要求
假設把某股票的價格按照時間先後順序儲存在陣列中,請問買賣該股票一次可能獲得的最大利潤是多少?
示例 1:
輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。
注意利潤不能是 7-1 = 6, 因為賣出價格需要大於買入價格。
示例 2:
輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種情況下, 沒有交易完成, 所以最大利潤為 0。
限制:
0 <= 陣列長度 <= 10^5
2)我的解法
class Solution {
public int maxProfit(int[] prices) {
int result=0,start=Integer.MAX_VALUE;
for(int i=0;i<prices.length;i++){
if(prices[i]<=start)start=prices[i];
else result=Math.max(result,prices[i]-start);
}
return result;
}
}
3)其他解法
class Solution {
public int maxProfit(int[] prices) {
int cost = Integer.MAX_VALUE, profit = 0;
for(int price : prices) {
cost = Math.min(cost, price);
profit = Math.max(profit, price - cost);
}
return profit;
}
}
作者:jyd
連結:link
來源:力扣(LeetCode)
4)自己的優化程式碼
class Solution {
public int maxProfit(int[] prices) {
int result=0,start=Integer.MAX_VALUE;
for(int i=0;i<prices.length;i++){
start=Math.min(prices[i],start);
result=Math.max(result,prices[i]-start);
}
return result;
}
}
5)學到的東西
動態規劃
70、求1+2+…+n(64、Medium)
1)題目要求
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
示例 1:
輸入: n = 3
輸出: 6
示例 2:
輸入: n = 9
輸出: 45
限制:
1 <= n <= 10000
2)我的解法
這題好奇葩。。。
沒想出來
3)其他解法
class Solution {
public int sumNums(int n) {
boolean x = n > 1 && (n += sumNums(n - 1)) > 0;
return n;
}
}
作者:jyd
連結: link
來源:力扣(LeetCode)
4)自己的優化程式碼
class Solution {
public int sumNums(int n) {
int sum=n;
boolean flag=n>0&&(sum+=sumNums(n-1))>0;
return sum;
}
}
5)學到的東西
&&和||的短路
相關文章
- LeetCode|劍指 Offer 49.醜數LeetCode
- LeetCode 劍指 Offer 05. 替換空格LeetCode
- 《劍指offer》JAVA題解,LeetCode評測JavaLeetCode
- LeetCode-劍指Offer刷題記錄LeetCode
- 劍指OFFER
- Leetcode 劍指 Offer 40. 最小的k個數LeetCode
- 【leetcode】劍指 Offer 16. 數值的整數次方LeetCode
- leetcode *劍指 Offer 47. 禮物的最大價值LeetCode
- LeetCode 劍指 Offer 65. 不用加減乘除做加法LeetCode
- 劍指offer導航
- 劍指 offer21
- 劍指offer16
- 劍指 offer20
- 劍指offer-JavaScript版JavaScript
- 【劍指Offer】矩形覆蓋
- 劍指Offer題解合集
- 劍指offer——跳臺階
- 六、劍指 Offer(25~29)
- 刷題記錄:劍指offer+遇到的筆試題+LeetCode筆試LeetCode
- Leetcode 劍指 Offer 03. 陣列中重複的數字LeetCode陣列
- 《Leetcode of December》劍指 Offer 67. 把字串轉換成整數LeetCode字串
- leetcode 劍指 Offer 48. 最長不含重複字元的子字串LeetCode字元字串
- leetcode 102 劍指Offer 32 二叉樹的層次遍歷LeetCode二叉樹
- 劍指offer第41~50題
- 劍指 offer(1) -- 陣列篇陣列
- 【劍指offer】【2】字串的空格字串
- 劍指offer刷題記錄
- 劍指offer-第2章
- LeetCode C++ 劍指 Offer 64. 求1+2+…+n【Bit Manipulation】中等LeetCodeC++
- 【劍指offer】2.替換空格
- 《劍指 Offer》棧實現佇列佇列
- 劍指offer刷題day02
- 劍指offer第49題 醜數
- 劍指offer-替換空格02
- 劍指offer解析-上(Java實現)Java
- 劍指offer解析-下(Java實現)Java
- 劍指offer 變態跳臺階
- 劍指Offer 撲克牌順子