本着练习的目的,建议不要取巧,胜一时易,时时胜难
1.从排序数组中删除重复项
难点:
nums去重之后为什么会改变数组大小 ?what? val是去重后的索引,但nums是素组啊,打印这个索引出现了数组
个人理解:
// 我是长度,超过的删除
int len = removeDuplicates(nums);
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
public class Solution {
public int RemoveDuplicates(int[] nums) {
if(nums.Length<=0)
{
return 0;
}
int val=0;
//排序
for(int i=0;i<nums.Length;i++)
{
if(nums[i]!=nums[val])
{
//出现新的数 給个位置
val++;
nums[val]=nums[i];
}
}
//索引从0开始,补齐数组长度
val+=1;
//nums去重之后为什么会改变数组大小 ?what? val是去重后的索引,但nums是素组啊,打印这个索引出现了数组
return val;
}
}
2.寻找数组的中心索引
难点:尽量少的使用for循环
public class Solution {
public int PivotIndex(int[] nums) {
int outStr= -1;
int num1=0;;
for(int i=0;i<nums.Length;i++)
{
num1+=nums[i];
}
for(int i=0;i<nums.Length;i++)
{
int num=0;
//不能使用left= (sum-i)/2
for(int j=0;j<i;j++)
{
num+=nums[j];
}
if(num*2 +nums[i]==num1)
{
outStr =i;
break;
}
}
return outStr;
}
}
3.买卖股票的最佳时机 II
三种解法
https://blog.csdn.net/qq_27480345/article/details/86490478
难点:
1.卖出当天依然可以买入
2.哪天买卖最合适,不是单天最大收益,而是累计最大收益;
3.利益差的递增(只要能交易就进行利益差的累加)
public int MaxProfit(int[] prices) {
int sum=0;
//假设第二天开始卖出
for(int i=1;i<prices.Length;i++)
{
//是否可以卖出
if(prices[i]>prices[i-1])
{
//计算所有收益,并进行累加
sum+=prices[i]-prices[i-1];
}
}
return sum;
}
4.旋转数组
难点:不知道为什么要叫旋转数组,利用取余重新设定数组的索引
var nums = arry;
int k = 3;
//超出取余
k %= nums.Length;
int[] arr = new int[nums.Length];
int n = nums.Length;
for (int i = 0; i < nums.Length; i++)
{
//从目标位置重新排序
arr[(i + k) % n] = nums[i];
}
arr.CopyTo(nums, 0);
5.存在重复元素
public class Program {
public static void Main(string[] args) {
int[] nums = null;
nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 7 };
var res = ContainsDuplicate(nums);
Console.WriteLine(res);
nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
res = ContainsDuplicate2(nums);
Console.WriteLine(res);
nums = new int[] { 1, 2, 3, 3, 5, 6, 7, 8 };
res = ContainsDuplicate3(nums);
Console.WriteLine(res);
Console.ReadKey();
}
private static bool ContainsDuplicate(int[] nums) {
//暴力解法
for(int i = 0; i < nums.Length; i++) {
for(int j = i + 1; j < nums.Length; j++) {
if(nums[i] == nums[j]) return true;
}
}
return false;
}
private static bool ContainsDuplicate2(int[] nums) {
//先排序,再使用单循环比较相邻值
Array.Sort(nums);
for(int i = 0; i < nums.Length - 1; i++) {
if(nums[i] == nums[i + 1]) return true;
}
return false;
}
private static bool ContainsDuplicate3(int[] nums) {
//哈希法
var dic = new Dictionary<int, int>();
foreach(var num in nums) {
if(dic.ContainsKey(num)) return true;
dic[num] = 0;
}
return false;
}
}
6.只出现一次的数字
线性时间复杂度:要求我们的代码时间复杂度最高为O(n),不能有嵌套循环等。
不使用额外空间:要求空间复杂度最高为O(1)。
方法一(比较法):
public static int singleNumber(int[] nums) {
Arrays.sort(nums);
// 排序数组 思路:先对数组进行排序,然后对 nums[i] 和 nums[i + 1]进行比较,如相等,i += 2继续下一组比较,直到取到不相等的一组。
for (int i = 0; i < nums.length - 1; i += 2) {
// 找到不相等的一组,直接返回
if (nums[i] != nums[i + 1]) {
return nums[i];
}
}
// 如果没有找到不相等的一组数据,直接返回数组的最后一个数字
return nums[nums.length - 1];
}
方法二(去重法):
思路:利用HashSet的特性,删除重复的数组元素,最后剩下一个单独的元素,返回即可。
public static int singleNumber(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (!set.add(nums[i])) { // add成功返回true,如果set中已有相同数字,则add方法会返回false
set.remove(nums[i]); // 删除重复出现的数字
}
}
return set.iterator().next();9 }
方法三(求差法):
思路:先对数组排序,显而易见的,单独出现一次的数据必然是出现在数组下标为偶数的位置(下标从0开始),那么所有奇数下标的元素之和减去偶数下标的元素之和,就是需要求得的结果。
public static int singleNumber(int[] nums) {
int num = 0;
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
// 偶数下标位置 num += nums[i],奇数下标位置 num -= nums[i]
num = i % 2 == 0 ? num + nums[i] : num - nums[i];
}
return num;
}
方法四(异或法):
思路:根据异或运算的特点,相同的数字经过异或运算后结果为0,除单独出现一次的数字外,其他数字都是出现两次的,那么这些数字经过异或运算后结果一定是0。而任何数字与0进行异或运算都是该数字本身。所以对数组所有元素进行异或运算,运算结果就是题目的答案。
public static int singleNumber(int[] nums) {
int num = 0;
for (int i = 0; i < nums.length; i++) {
num = num ^ nums[i];
}
return num;
}