算法Ⅰ(数组篇)

26、删除排序数组中的重复项

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

//双指针
int removeDuplicates(vector<int>& nums) {
  int i = 0;
  for (int j = 1; j < nums.size(); j++) {
    if (nums[i] != nums[j]) nums[++i] = nums[j];
  }
  return ++i;
}

122、买卖股票的最佳时机

给定一个数组 prices ,其中 prices[i] 表示股票第 i 天的价格。
在每一天,你可能会决定购买和/或出售股票。你在任何时候 最多 只能持有一股股票。你也可以购买它,然后在同一天出售。返回你能获得的最大利润 。

思路:相邻两个元素之差为利润,正利润的累加即是可获取的最大利润。

int maxProfit(vector<int>& prices) {
  int profit = 0;
  for (int i = 0; i < prices.size() - 1; i++)
    if (prices[i + 1] - prices[i] > 0) profit += prices[i + 1] - prices[i];
  return profit;
}

189、旋转数组

给定一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

void rotate(vector<int>& nums, int k) {
  vector<int> v;
  k = k % nums.size(); //小坑
  for (int i = nums.size() - k; i < nums.size(); i++) {
    v.push_back(nums[i]);
  }
  for (int i = 0; i < nums.size() - k; i++) {
    v.push_back(nums[i]);
  }
  nums = v;
}
//解法二:多次翻转
void reverse(vector<int>& nums, int start, int end) {
  while (start < end) {
    swap(nums[start], nums[end]);
    start += 1;
    end -= 1;
  }
}
void rotate(vector<int>& nums, int k) {
  k %= nums.size();
  reverse(nums, 0, nums.size() - 1);
  reverse(nums, 0, k - 1);
  reverse(nums, k, nums.size() - 1);
}

136、存在重复元素

给你一个整数数组 nums 。如果任一值在数组中出现至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false。

bool containsDuplicate(vector<int>& nums) {
  sort(nums.begin(), nums.end());
  bool tmp = false;
  for (int i = 0; i < nums.size() - 1; i++) {
    if (nums[i + 1] - nums[i] == 0) {
      tmp = true;
    }
  }
  return tmp;
}

//解法二
bool containsDuplicate(vector<int>& nums) {
  sort(nums.begin(), nums.end());
  // unique返回非重复元素的下一个元素,end()返回最后一个元素的后一个位置
  return std::unique(nums.begin(), nums.end()) != nums.end();
}

350、只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

int singleNumber(vector<int>& nums) {
  int result = 0;
  for (int i = 0; i < nums.size(); i++) result ^= nums[i];
  return result;
}

非常巧妙的一题,看完解法惊掉下巴~~

350、两个数组的交集

给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

思路一

  1. 先对两个数组进行排序,然后使用两个指针,分别指向两个数组开始的位置。

  2. 如果两个指针指向的值相同,说明这个值是他们的交集,就把这个值加入到数组中,然后两个指针在分别往后移一步。

  3. 如果两个指针指向的值不同,那么指向的值相对小的往后移一步,相对大的先不动,然后再比较。一直重复上面的操作,直到其中一个指针不能再移动为止。

vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
  sort(nums1.begin(), nums1.end());
  sort(nums2.begin(), nums2.end());

  vector<int> v;
  int i = 0, j = 0;
  while (i < nums1.size() && j < nums2.size()) {
    if (nums1[i] < nums2[j]) {
      i++;
    } else if (nums1[i] > nums2[j]) {
      j++;
    } else {
      v.push_back(nums1[i]);
      i++;
      j++;
    }
  }
  return v;
}

//迭代器
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
  sort(nums1.begin(), nums1.end());
  sort(nums2.begin(), nums2.end());

  vector<int> v;
  for (auto it1 = nums1.begin(), it2 = nums2.begin();
       it1 != nums1.end() && it2 != nums2.end();) {
    if (*it1 < *it2) {
      it1++;
    } else if (*it1 > *it2) {
      it2++;
    } else {
      v.push_back(*it1);
      it1++;
      it2++;
    }
  }
  return v;
}

思路二


//hashmap
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
  map<int, int> mp;
  vector<int> v;
  for (int i = 0; i < nums1.size(); i++) {
    if (mp[nums1[i]]) {
      mp[nums1[i]]++;
    } else {
      mp[nums1[i]] = 1;
    }
  }
  for (int i = 0; i < nums2.size(); i++) {
    if (mp.count(nums2[i])) {
      v.push_back(nums2[i]);
      mp[nums2[i]]--;
      if (mp[nums2[i]] == 0) {
        mp.erase(nums2[i]);
      }
    }
  }
  return v;
}

66、加一

给定一个由 整数 组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。

vector<int> plusOne(vector<int>& digits) {
  int len = digits.size();
  for (int i = len - 1; i >= 0; i--) {
    if (digits[i] == 9) {
      digits[i] = 0;
    } else {
      digits[i]++;
      return digits;
    }
  }
  digits.insert(digits.begin(), 1);
  return digits;
}

283、移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。

//双指针
void moveZeroes(vector<int>& nums) {
  int left = 0, cnt = 0, len = nums.size();
  for (int right = 0; right < len; right++) {
    if (nums[right] != 0) {
      nums[left] = nums[right];
      left++;
    } else
      cnt++;
  }
  for (int i = len - 1; i > len - cnt - 1; i--) {
    nums[i] = 0;
  }
}

//改进版本
void moveZeroes(vector<int>& nums) {
  int left = 0, cnt = 0, len = nums.size();
  for (int right = 0; right < len; right++) {
    if (nums[right] != 0) {
      swap(nums[right], nums[left]);
      left++;
    }
  }
}

把非零元素移到前面,再在最后补0。

1、两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。

//O(n^2)
vector<int> twoSum(vector<int>& nums, int target) {
  vector<int> v;
  for (int i = 0; i < nums.size(); i++) {
    for (int j = i + 1; j < nums.size(); j++)
      if (nums[i] + nums[j] == target) {
        v.push_back(i);
        v.push_back(j);
        break;
      }
  }
  return v;
}

//hash
vector<int> twoSum(vector<int>& nums, int target) {
  unordered_map<int, int> hashTable;
  for (int i = 0; i < nums.size(); i++) {
    hashTable[nums[i]] = i;
  }
  for (int i = 0; i < nums.size(); i++) {
    auto it = hashTable.find(target - nums[i]);
    if (it != hashTable.end() && (it->second) != i) {
      return {it->second, i};
    }
  }
  return {};
}

36、有效的数独(*)

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3宫内只能出现一次。(请参考示例图)

注意:

  1. 一个有效的数独(部分已被填充)不一定是可解的。
  2. 只需要根据以上规则,验证已经填入的数字是否有效即可。
  3. 空白格用 ‘.’ 表示。
bool isValidSudoku(vector<vector<char>>& board) {
  int row[9][9];  //行数组,第二维记录数字出现的个数
  int col[9][9];
  int box[3][3][9];  //九宫格数字记录
  memset(row, 0, sizeof(row));
  memset(col, 0, sizeof(col));
  memset(box, 0, sizeof(box));

  for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
      char c = board[i][j];  //当前元素
      if (c != '.') {
        //下标
        int index = c - '0' - 1;
        row[i][index]++;
        col[j][index]++;
        box[i / 3][j / 3][index]++;
        if (row[i][index] > 1 || col[j][index] > 1 ||
            box[i / 3][j / 3][index] > 1) {
          return false;
        }
      }
    }
  }
  return true;
}

48、旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

//画图,查看矩阵特点
void rotate(vector<vector<int>>& matrix) {
  int row = matrix.size();
  for (int i = 0; i < row; i++) {
    for (int j = i + 1; j < row; j++) {
      swap(matrix[i][j], matrix[j][i]);
    }
  }
  for (int i = 0; i < row; i++) {
    for (int j = 0; j < row / 2; j++) {
      swap(matrix[i][j], matrix[i][row - j - 1]);
    }
  }
}

先转置再镜像。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eynoZzzzc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值