算法笔记(一)
一、给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
这里用到了异或的思想,异或就是相同为0,不同为1。用二进制表示更为直观,例1 [2,2,1]转换为二进制就是[10,10,01],按位异或,10和10异或后得00,然后00与01异或,得01,即最终答案。如果使例2的情况依次异或可能手算有些慢,因异或有交换律,所以可以直接看成同数异或为0,得到答案4。代码如下:
public class Solution {
public int SingleNumber(int[] nums) {
int a=0;
for(int i=0;i<nums.Length;i++){
a^=nums[i];
}
return a;
}
}
二、给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在众数。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
一开始的思路是先对数组排序,然后用两层for循环遍历数组,用count计数,count值最大的为众数,结果发现无法把count值和对应的数联系起来…
然后看了别人的解题思路发现数学方法很简单,因为题目给定有众数,所以数组中间的那个数必然是众数。相应代码如下:
public class Solution {
public int MajorityElement(int[] nums) {
Array.Sort(nums);
int a=nums.Length/2;
return nums[a];
}
}
注:/直接忽略小数,%取余(容易忘记),之前就是忘记了,用了Math.Floor向下取整结果报错了。
然后学习了摩尔投票法,题中给定众数是在数组中出现次数大于 ⌊ n/2 ⌋ 的元素,大致思想可以概括为数组内不同元素两两抵消,因为众数大于 ⌊ n/2 ⌋ ,所以剩下来的那个数就是众数。
public class Solution {
public int MajorityElement(int[] nums) {
int i,num,count=1;
num=nums[0];
for(i=1;i<nums.Length;i++){
if(count==0) num=nums[i];//count代表num出现的次数,若count==0(即当前num已被抵消,则将更换比较值)
if(num==nums[i]) count++;
else count--;
}
return num;
}
}
三、搜索二维矩阵
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
思路:遍历数组每一行,对每一行执行二分查找。left为左指针,right为右指针,middle=(left+right)/2。若target==matrix[i,middle],则找到目标,返回true;若target>middle,则说明target位于middle右侧,因此把左指针移至middle右侧一位,即left=middle+1;若target<middle,则说明target位于middle左侧,同理把右指针移至middle左侧一位,即right=middle-1。执行以上操作的前提是left<=right。
代码如下:
public class Solution {
public bool SearchMatrix(int[,] matrix, int target) {
int i,left,right,middle;
for(i=0;i<matrix.GetLength(0);i++){
left=0;
right=matrix.GetLength(1)-1;
while(left<=right){
middle=(left+right)/2;
if(matrix[i,middle]==target) return true;
else if(matrix[i,middle]<target) left=middle+1;
else right=middle-1;
}
}
return false;
}
}
分治算法:
思路是左下角的元素比它所在列的其他元素大,比它所在行的其他元素小,所以每次将target与左下角元素比较,就可以直接删去一行或者一列。代码如下:
public class Solution {
public bool SearchMatrix(int[,] matrix, int target) {
int i=matrix.GetLength(0)-1;
int j=0;
while(i>=0&&j<matrix.GetLength(1)){
if(target==matrix[i,j]) return true;
else if(target>matrix[i,j]) j++;
else i--;
}
return false;
}
}