代碼隨想錄算法訓練營|第一天|704.二分查找、27.移除元素。刷题心得(c++)

目录

讀題

704. 二分查找

自己看到题目的第一想法

看完代码随想录之后的想法

27. 移除元素

自己看到题目的第一想法

看完代码随想录之后的想法

704. 二分查找 - 實作

思路

Code

27. 移除元素 實作

思路

Code

Submit 第一次: 兩個都Submit 失敗

總結


讀題

704. 二分查找

自己看到题目的第一想法

在看到的一瞬間,對於這個題目使用二分法去解的理解不難,甚至感覺自己馬上就可以解出來

看完代码随想录之后的想法

看完代碼隨想錄後,忽然意識到自己不是了解,只是因為沒有碰到這個問題,當下看完卡哥的講解後,才發現自己沒有注意到的問題

  1. 對於區間的定義不明確,之前根本沒有去思考是左閉右閉、還是左閉右開
  2. 對於buffer overflow 的問題也沒有去思考

並且在訓練營中看到同伴有詢問((right - left) >> 1)這個操作,才發現自己也可以來嘗試使用這樣的bitwise 右移操作將數值除以2的n次方,來嘗試使用看看。

27. 移除元素

自己看到题目的第一想法

在這個題目中,看到移除元素的操作很直覺,就是刪掉,在實作上也有了解到要作覆蓋的動作,解釋如下

數組因為是一個連續記憶體位置,假設一個a陣列刪除a[2],那就是需要用覆蓋的,如果直接把值刪除,假設取a[2]這個元素,並不會如我們預想的出現原本a[3]的數值,所以在刪除元素上,是需要將a[2]後面的值依序往前移

看完代码随想录之后的想法

在看完代碼隨想錄之後,發現自己之前的作法很沒有效率,利用雙指針,可以讓刪除這個動作由原本的O(n^2) 縮減到 O(n) 值行完成,方法很巧妙,但是之前自己就是想不到,接下來會來試試看暴力解以及快慢指針的實作

704. 二分查找 - 實作

思路

實作三個作法

  1. 左閉右閉
    1. Left == Right 是有意義的
    2. left = 0, right = nums.size() - 1;
    3. while( left ≤ right)
    4. middle = left + ( right - left ) / 2
    5. if nums[middle] > target, then right = middle -1
    6. if nums[middle] < target, then left = middle + 1
  2. 左閉右開
    1. Left == Right 是沒有意義的,因為搜尋範圍中不包含 right
    2. left = 0, right = nums.size();
    3. while( left < right)
    4. middle = left + ( right - left ) / 2
    5. if nums[middle] > target, then right = middle
    6. if nums[middle] < target, then left = middle + 1
  3. 使用bitwise進行操作
    1. middle = left + (( right - left ) >> 1)

Code

  1. 左閉右閉

    class Solution{
    public:
    	int search(vector<int>& nums, int target){
    		int left = 0;
    		int right = nums.size() - 1;
    		int middle = 0;
    	
    	  while (left <= right){
    			middle = left + ((right - left) / 2);
    			if(nums[middle] > target){
    				right = middle - 1;
    			}		
    			else if(nums[middle] < target){
    				left = middle + 1;	
    			}
    			else{
    				return middle;
    			}
    		}
    	return -1;
    	}
    };
    
  2. 左閉右開

    class Solution{
    public:
    	int search(vector<int>& nums, int target){
    		int left = 0;
    		int right = nums.size();
    		int middle = 0;
    	
    	  while (left < right){
    			middle = left + ((right - left) / 2);
    			if(nums[middle] > target){
    				right = middle;
    			}		
    			else if(nums[middle] < target){
    				left = middle + 1;	
    			}
    			else{
    				return middle;
    			}
    		}
    	return -1;
    	}
    };
    
  3. 左閉右閉,使用bitwise操作

    class Solution{
    public:
    	int search(vector<int>& nums, int target){
    		int left = 0;
    		int right = nums.size();
    		int middle = 0;
    	
    	  while (left < right){
    			middle = left + ((right - left) >> 1);
    			if(nums[middle] > target){
    				right = middle;
    			}		
    			else if(nums[middle] < target){
    				left = middle + 1;	
    			}
    			else{
    				return middle;
    			}
    		}
    	return -1;
    	}
    };
    

27. 移除元素 實作

思路

  1. 暴力解
    1. 因為 0 ≤ nums[i] ≤ 50 ,並且 0 ≤ val ≤ 100,所以假設nums[i] > 50,則陣列中沒有需要刪除的元素,直接return 原陣列長度
    2. 設定k = nums.size();
    3. 建立第一個迴圈,因為 0 ≤ nums.length ≤ 100 所以,設置for迴圈,遍歷k的數量,設定為k是因為陣列長度會有改變
    4. 設定一個判斷式,假設 nums[i] == val,則執行第二個迴圈
    5. 第二個迴圈,假設 nums[i] == val 代表目前陣列位置為 i 中的數值需要被後一個值覆蓋,所以設定j = i; j < k - 1; j++,k - 1的原因是,因為要使用後面一個數值,所以要避免overflow的狀況發生,所以設定k-1
    6. 跳出第二個迴圈後,仍然在判斷式的範圍當中,設置k--; 將nums.size() - 1,並且因為所有數值往前一位,所以也要將i--;
    7. 跑完迴圈後 return k;
  2. 快慢指針法
    1. 因為 0 ≤ nums[i] ≤ 50 ,並且 0 ≤ val ≤ 100,所以假設nums[i] > 50,則陣列中沒有需要刪除的元素,直接return 原陣列長度
    2. 設定兩個指針
      1. 快指針 = 0;
      2. 慢指針 = 0;
    3. 建立一個for 迴圈完整跑完陣列範圍,i = 0; i < nums.size(); i++ → 快指針走的位置
    4. 設定一個條件是,只有快指針指到不是val,則慢指針的數值才增加
    5. 跑完迴圈後,回傳慢指針的數值, 因為陣列的起始為0;

Code

  1. 暴力解
class Solution{
public:
	int RemoveElement(vector<int>&nums, int val){
			if(val > 50){
				return nums.size();
			}
			int k = nums.size();
			for( int i = 0; i < k; i++){
				if(nums[i] == val){
					for(int j = i; j < k - 1; j++){
						nums[j] = nums[j + 1];
					}
					i--;
					k--;
				}
			}
			return k;
	}
};
  1. 快慢指針解
class Solution{
public:
	int RemoveElement(vector<int>&nums, int val){
			if(val > 50){
				return nums.size();
			}
			int FastPoint = 0;
			int SlowPoint = 0;
			for( FastPoint = 0; FastPoint < 100; FastPoint++){
				if(nums[FastPoint] != val){
					nums[SlowPoint] = nums[FastPoint];
					SlowPoint++;
				}
			}
			return SlowPoint;
	}
};

Submit 第一次: 兩個都Submit 失敗

  1. 暴力解
    在第二個迴圈中,我會把當下陣列下標為i 值由i+1來替換掉,後續依序補上但出了這個迴圈後,如果沒有i-- 那第一個迴圈就會在 i ++ ,但如果這樣的話,這個下標原本為i + 1 的值,會沒有被檢查到,就被省略掉了,所以必須在陣列被修改的時候,將i 也向前移動一位
  2. 快慢指針解
    for迴圈太快去寫範圍是100,導致程式執行失敗,應該要改為nums.size();慢指針的數值不能加一,忽略了在最後一次,慢指針仍然會在結束時加一,數值剛好就是nums.size().

總結

● 自己实现过程中遇到哪些困难

  • 704. 二分查找
    對於區間的定義明確後,解起來就沒有太困難的地方,主要是要把思路想好,讓自己可以跟著思路走

  • 27. 移除元素

    真實說明了,概念很清楚,實作就矇了,在暴力解跟快慢指針上都在小細節上敗了

    • 暴力解

      第二個迴圈中,我會把當下陣列下標為i 值由i+1來替換掉,後續依序補上,沒有i-- ,導致錯誤產生

    • 快慢指針

      for迴圈太快去寫範圍是100,導致程式執行失敗,應該要改為nums.size();

● 今日收获,记录一下自己的学习时长

總結了這兩題的所遇到的困難,感覺是在自己對於定義清不清晰

二分查找的定義有釐清清楚,所以在代碼的實現上沒有太大的問題

移除元素

  • 暴力解沒有去思考好移動的定義
  • 快慢指針沒有去想清楚執行的範圍

今天在學習上大約花了兩到三小時,主要是在讀題記錄筆記、寫題記錄思路以及最後的統整花了比較多時間,但這些紀錄東西記錄下來後,其實更加知道自己的不足在哪

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值