文章目录
前言
今天是第一天,那咱门就来简单一点寄到题目来玩玩吧,不为别的就为了心情愉悦。
这里虽然是简单题目,但是没想到没注意几个变量愣是调了小半天。还是要细心一点呀。
两数之和
乍一看这个题目,其实还是挺简单的,最好想到的方法其实就是拿两个指针一前一后去扫描,然后把两个数字加起来查看是不是我们想要的结果。
class Solution {
public int[] twoSum(int[] nums, int target)
{
int n = nums.length;
for (int i = 0; i < n; ++i)
{
for (int j = i + 1; j < n; ++j)
{
if (nums[i] + nums[j] == target)
{
return new int[]{i, j};
}
}
}
return new int[0];
}
}
但是的话我们其实还是有更加nice方法的,那就是我们完全是可以使用哈希函数来降低时间复杂度,其实就是使用字典在java里面叫做map
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; ++i) {
if (map.containsKey(target - nums[i])) {
return new int[]{map.get(target - nums[i]), i};
}
map.put(nums[i], i);
}
return new int[0];
}
}
我们可以直接把我们的数值元素和对应的下标存到 map 里面。然后你不是要求(假设求9 那么我直接遍历 9-元素等不等于 map里面的另一个元素)并且我们可以直接把我们的寻找和元素添加放在一起,因为知道找到了我们就没有必要再往下添加元素,然后扫描了。
为了便于理解你可以直接查看这个 python 代码
class Solution:
def twoSum(self, nums, target):
hashtable = {}
for i, num in enumerate(nums):
if target - num in hashtable:
return [hashtable[target - num], i]
hashtable[nums[i]] = i
return []
哦对了有必要说一下的是那个现在好像不少人使用的python语法是3.9x的,虽然没啥问题但是看起来怪怪的。
回文数
这个其实很简单,最简单的就是说,你变成字符串嘛,然后去扫描从前面的到后面的两个指针(数组下标指向)去扫描。
但是我们其实可以优化一下,原理还是一样的,都是两头去扫描。但是区别是,前者我们要转化为字符串然后去扫描,这里会带来一些内存消耗,另一个则是使用取余数法,然后拼接数字,也是前后扫描。
class Solution {
public boolean isPalindrome(int x) {
if(x<0||x%10==0 && x!=0){
//负数和一位数都不是回文
return false;
}
int rev = 0;
//我们对半提取,个位拿出来然后依次
while (x>rev){
rev = rev * 10 + x%10;
x /=10;
}
return x==rev||x==rev/10;
}
}
举个例子 1221
我们对半 把最后面的 1 和 2拿出来 逆向组合不就是 12 嘛,如果这个12 和 前面的12 相等不是是回文嘛。
这里要注意的细节就是 12321 有些是奇数的,在我们代码里面是从后面组合的也就是 rev = 123 退出循环 x= 12 此时,所以 x == rev/10 才成立。
罗马数字转整数
关于这题就说明两点
第一点是:
第二点是:
class Solution {
public int romanToInt(String s) {
Map<Character,Integer> map = new HashMap<>();
String chars = "IVXLCDM";
int j = 1;
for(int i=1;i<=chars.length();i++){
if(i!=1)
if (i%2==0)
j*=5;
else
j*=2;
map.put(chars.charAt(i-1),j);
}
j = 0;
for(int i=0;i<s.length();i++){
int value = map.get(s.charAt(i));
if(i<s.length()-1 && value<map.get(s.charAt(i+1))){
j-=value;
}
else
j+=value;
}
return j;
}
}
有效括号
这个没啥好说的。栈呗。
class Solution {
public boolean isValid(String s) {
if(s == null || s.length() == 1){
return false;
}
Stack<Character> chars = new Stack<Character>();
for(int i=0;i<s.length();i++){
char c = s.charAt(i);
if(c=='(' || c=='[' || c=='{'){
chars.push(c);
}
else {
if(chars.isEmpty())
return false;
if(c==')'&& chars.peek()=='('){
chars.pop();
}else if (c==']' && chars.peek()=='['){
chars.pop();
}
else if (c=='}' && chars.peek()=='{'){
chars.pop();
}
else
return false;
}
}
if(chars.isEmpty())
return true;
return false;
}
}
合并两个有序链表
这里要注意的是那个
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
这个是他们给的那个链表的定义,一定要先给一个元素值。
class Solution6 {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode res = new ListNode(0);
ListNode cur = res;
while (list1!=null && list2!=null){
if(list1.val > list2.val){
cur.next = list2;
list2 = list2.next;
cur = cur.next;
}
else {
cur.next = list1;
list1 = list1.next;
cur = cur.next;
}
}
if(list1==null){
cur.next = list2;
}
else {
cur.next = list1;
}
return res.next;
}
}
这边我们是采用了牺牲空间的策略,这里还是可以优化的,我们可以选择直接把两个直接合并到list1或者list2那边,直接对list1这边操作,但是不太好理解,可以直接使用递归,但是我觉得这个消耗也不少。
最长公共前缀
这个题目是挺简单的,但是我写的时候没注意,老是过不了,然后查了一下,但是发现那个给出的标准代码是有逻辑问题的,虽然能够通过测试集。
题目:
我们就先来看看那个标准代码
class Solution {
public String longestCommonPrefix(String[] strs)
{
if (strs == null || strs.length == 0)
{
return "";
}
String prefix = strs[0];
int count = strs.length;
for (int i = 1; i < count; i++)
{
prefix = longestCommonPrefix(prefix, strs[i]);
if (prefix.length() == 0)
{
break;
}
}
return prefix;
}
public String longestCommonPrefix(String str1, String str2) {
int length = Math.min(str1.length(), str2.length());
int index = 0;
while (index < length && str1.charAt(index)== str2.charAt(index))
{
index++;
}
return str1.substring(0, index);
}
}
发现没有,他是什么,他是拿出第一个单词,然后用这个第一个单词和剩下的单词去对比,也就是执行
longestCommonPrefix( ) 但是关于这个函数,你自己看看它做了什么,就是对比两个单词前面的共同点,然后返回两个单词之间的公共前缀,然后返回给prefix,问题来了假设有三个单词,第一个和第二个单词的前缀为 ab 第一个和第三个为 abc。执行第一次 strs[1] prefix为 ab 第二次 strs[2] prefix 为 abc 然后结束循环,此时prefix 为 abc 问题来了,显然三个单词里面的前缀应该是ab,而不是abc。但是我不知道为什么这代码能够过测试集!!!
ok 那么来看看我这边的代码
class Solution {
public String longestCommonPrefix(String[] strs) {
String firstworld = strs[0];
String answer = "";
int index = 0;
boolean flag = true;
out:for(int i = 0;i<firstworld.length();i++){
char c = firstworld.charAt(i);
for(int j=1;j<strs.length;j++){
if(i>=strs[j].length()){
break out;
}
else {
if(c !=strs[j].charAt(i) )
flag = false;
}
}
if(flag)
index ++;
}
answer = firstworld.substring(0,index);
return answer;
}
}
思路也是一样的,拿出第一个单词,但是我是直接拿第一个单词的第一个字母去和剩下的单词对应位置的字母去比对,一旦返现比对的字母数字,超过了当前单词的长度,那么说明这个单词整个都是最长前缀,如果没有然后发现当前字母对不到了,那么前面的都是相同前缀。
当然你还可以换个方式来扫描,以单词为主。