ARTS挑战第十三周

1.Algorithm

1.1 最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z 。

1.1.1 解法一 依次比较每个位置上的元素

从第一个字符串的第一个元素开始遍历,
如果其它字符串在相同位置也是该元素则继续,否则返回

注意:
输入可能是空字符串[]
输入是[a,a],[a]要判断当前位置小于字符串长度
方法String.substring(beginIndex,endIndex)输出不包括endIndex位置

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs.length == 0) return "";
        int i = 0;
        char temp;
        for (i = 0; i < strs[0].length(); i++) {
            temp = strs[0].charAt(i);
            for (int j = 1; j < strs.length; j++) {
                if (strs[j].length() == i || !(temp == strs[j].charAt(i))) {
                    return strs[0].substring(0, i);
                }
            }
        }
        return strs[0].substring(0, i);
    }
}

1.1.2 解法二 先将第一个字符串默认为最长

公共前缀==第一个字符串
公共前缀和第二个字符串==》公共前缀
公共前缀和第三个字符串==》公共前缀

如果公共前缀为""则退出
否则使用String.indexOf()如果结果不等于0,那么去掉公共前缀的末尾再比较

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs.length == 0) return "";
        String temp = strs[0];
        for (String str : strs) {
            while (temp.length() != 0) {
                if (str.indexOf(temp) != 0) {
                    temp = temp.substring(0, temp.length() - 1);
                } else {
                    break;
                }
            }
        }
        return temp;
    }
}

时间复杂度:O(S) S是字符数组长度
控件复杂度:O(1)

1.1.3 分治法

  1. 将数组分为左右两部分
  2. 最长公共前缀=左最长 与 右最长比较
  3. 左最长 重复1 2
  4. 右最长 重复1 2
  5. 当数组元素只有一个时,最长为本身,返回当前为最长公共前缀
  6. 获取左最长与右最长的比较后的公共前缀
class Solution {
    public String longestCommonPrefix(String[] strs) {
	    if(strs.length == 0) return;
		return longestCommonPrefix(strs,1,strs.length);
    }
	
	private String longestCommonPrefix(String[] ,int left ,right right){
		//临界点
		if(left == right)
			return(strs[left]);
		
		String leftResult = longestCommonPrefix(strs, left, (left + right) / 2);
		String rightResult = longestCommonPrefix(strs, (left + right) / 2, right);
		commonPrefix(leftResult, rightResult);
	}
	//比较两个字符串的公共前缀
	//方案1:依次比较相同位置的元素
	commonPrefix(String leftResult,String rightResult){
		for(int i = 0; i < leftResult.length(); i++){
			if(rightResult.length() <= i || rightResult.charAt(i)!= leftResult.charAt(i) )
				return leftResult.substring(0,i);
		}
	}
	//比较两个字符串的公共前缀
	//方案2:将一个字符串作为prefix,在比较中缩小prefix
	commonPrefix2(String leftResult,String rightResult){
		while(rightResult.indexOf(leftResult) != 0){
			leftResult = leftResult.substring(0,leftResult.length()-1);
			if(leftResult.isEmpty())
				return "";
		}
		return leftResult;
	}
}

1.1.4 二分查找

  • 首先获取最小的元素长度minLength
  • 将第一个元素从0到minLength作为profix;因为最长profix符合和任意一个匹配都是最长
  • 与其它元素循环比较时,不去从profix的第一个下标开始比较,而是使用二分查找来比较
  • 先比较从0到middle是否相等
  • 相等,那么再比较从0 到 middle=(left(middle+1) + right )/2
  • 不相等,那么再比较从0 到 middle=(left + right(middle-1) )/2
  • 直到right < left
  • 此时 profix = strs.substring(0,middle)
  • 注意:middle为数组的长度,比下标大1,起始left=1;right=strs.length;

典型二分查找:判断arr[middle]==val;判断是否相等
该二分查找:判断 strs[i].startWith(profix.substring(0,middle));判断是否公共前缀;

归纳:

  • 对数据源arr 和 profix进行二分
  • 二分后的值 arr[middle] 和 profix.substring(0,middle)
  • 判断是否满足条件 ==val 和 是所有元素的公共前缀
class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs.length == 0) return "";
        int height = Integer.MAX_VALUE;
        for (String str : strs) {
            height = Math.min(height, str.length());
        }
        int low = 1;

        while (low <= height) {
            int middle = (low + height) / 2;
            String profix = strs[0].substring(0, middle);
            if (isCommonPrefix(strs, profix)) {
                low = middle + 1;
            } else {
                height = middle - 1;
            }
        }
        //长度是几?
        return strs[0].substring(0, (low + height) / 2);
    }

    //比较两个字符串的公共前缀
    //方案3:二分查找
    private boolean isCommonPrefix(String[] strs, String profix) {
        for (int i = 1; i < strs.length; i++) {
            if (!strs[i].startsWith(profix))
                return false;
        }
        return true;
    }
}

1.1.5 前缀树

参考:前缀树实现

需要对最简单的前缀树添加size属性
如果size长度为1则说明是公共前缀

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs.length == 0) return "";
        Trie trie = new Trie();
        for (String str : strs) {
            trie.insert(str);
        }
        return trie.getProfixStr(strs[0]);
    }
    
    /**
     * 节点类
     */
    class TrieNode {
        private TrieNode[] trieNodes;
        //共有26个英文字母
        private final int length = 26;
        //是否为结尾节点
        private boolean isEnd;
        //非空节点长度
        private int size = 0;

        public TrieNode() {
            this.trieNodes = new TrieNode[length];
        }

        public void put(char ch, TrieNode trieNode) {
            this.trieNodes[ch - 'a'] = trieNode;
            size++;
        }

        public TrieNode get(char ch) {
            return this.trieNodes[ch - 'a'];
        }

        public boolean containsKey(char ch) {
            return this.trieNodes[ch - 'a'] != null;
        }

        public boolean isEnd() {
            return this.isEnd;
        }

        public void setEnd() {
            this.isEnd = true;
        }

        public int getSize() {
            return this.size;
        }
    }    
    //前缀树结构
    class Trie {
        //当前节点
        private TrieNode root;

        /**
         * Initialize your data structure here.
         */
        public Trie() {
            this.root = new TrieNode();
        }

        /**
         * Inserts a word into the trie.
         */
        public void insert(String word) {
            //从根节点开始
            TrieNode trieNode = this.root;
            for (int i = 0; i < word.length(); i++) {
                char currentChar = word.charAt(i);
                if (!trieNode.containsKey(currentChar))
                    trieNode.put(currentChar, new TrieNode());
                //下一个节点,处理下一个元素
                trieNode = trieNode.get(currentChar);
            }
            trieNode.setEnd();
        }


        //获取最长公共前缀
        public String getProfixStr(String str) {
            TrieNode trieNode = this.root;
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < str.length(); i++) {
                char currentChar = str.charAt(i);
                if (trieNode.getSize() != 1 || trieNode.isEnd())
                    return stringBuilder.toString();
                else {
                    stringBuilder.append(currentChar);
                    trieNode = trieNode.get(currentChar);
                }
            }
            return stringBuilder.toString();
        }
    }
}

2.Review

3.Tip

3.1 .net 使用 StateServer 保存session

场景:

应用程序部署在两台服务器,通过域名映射到两台服务器的ip A 和 B上面
当用户登录以后,访问的是服务器ip A,过段时间再次访问,域名解析可能会将ip映射到服务器ip B上
此时会发现session丢失

原因:

原始配置,两台服务器的session保存在各自服务器的 aspnet_state服务中

<sessionState 
	cookieless="UseCookies"
 	mode="StateServer" 
 	stateConnectionString="tcpip=127.0.0.1:42424" 
 	timeout="60" 
/>

解决方案:

两台服务器的session都存放到同一台服务器的aspnet_state服务中
需要开启42424端口的外部访问权限
打开注册表:
HKEY_LOCAL_MacHINE/SYSTEM/CurrentControlSet/Services/aspnet_state /Parameters 节点
AllowRemoteConnection的值改为1(1 为允许远程电脑的连接,0 代表禁止)
也可以修改aspnet_state服务的端口号Port,默认42424

测试方案

在浏览器通过两个ip A B访问两个服务器,session不能共享,因为不在同一个域下面

本地测试没有域名到ip的映射,尝试使用ngnix的反向代理,
访问同一个ip,分别轮询映射到两台服务器的地址上面,在这种情况下是否会共享session呢?

4.Share

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值